TestableMock
TestableMock
- 快速
Mock 任意调用:使被测类的任意方法调用快速替换为Mock 方法,实现" 指哪换哪" ,解决传统Mock 工具使用繁琐的问题。 - 访问被测类私有成员:使单元测试能直接调用和访问被测类的私有成员,解决私有成员初始化和私有方法测试的问题。
- 辅助测试
void 方法:利用Mock 校验器对方法的内部逻辑进行检查,解决无返回值方法难以实施单元测试的问题。 - 快速构造参数对象:生成任意多层嵌套的对象实例,并简化其内部成员赋值方式,解决被测方法参数初始化代码冗长的问题。
Hello World
依赖配置
在 build.gradle
文件中添加 TestableMock
依赖:
dependencies {
testImplementation('com.alibaba.testable:testable-all:0.5.2')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.5.2')
}
然后在测试配置中添加
test {
jvmArgs "-javaagent:${classpath.find { it.name.contains("testable-agent") }.absolutePath}"
}
然后相比以往
Mock 非构造方法,拷贝原方法定义到Mock 容器类,加@MockMethod 注解Mock 构造方法,拷贝原方法定义到Mock 容器类,返回值换成构造的类型,方法名随意,加@MockContructor 注解
覆写任意类的方法调用
首先为测试类添加一个关联的
public class DemoTest {
public static class Mock {
// 放置 Mock 方法的地方
}
}
在
// 原方法签名为`String substring(int, int)`
// 调用此方法的对象`"anything"`类型为`String`
@MockMethod(targetClass = String.class)
private String substring(int i, int j) {
return "sub_string";
}
当遇到待覆写方法有重名时,可以将需覆写的方法名写到
// 使用`targetMethod`指定需Mock的方法名
// 此方法本身现在可以随意命名,但方法参数依然需要遵循相同的匹配规则
@MockMethod(targetClass = String.class, targetMethod = "substring")
private String use_any_mock_method_name(int i, int j) {
return "sub_string";
}
有时,在
// Mock方法在参数列表首位增加一个类型为`String`的参数(名字随意)
// 此参数可用于获得当时的实际调用者的值和上下文
@MockMethod
private String substring(String self, int i, int j) {
// 可以直接调用原方法,此时Mock方法仅用于记录调用,常见于对void方法的测试
return self.substring(i, j);
}
覆写被测类自身的成员方法
有时候,在对某些方法进行测试时,希望将被测类自身的另外一些成员方法
// 被测类型是`DemoMock`
@MockMethod(targetClass = DemoMock.class)
private String innerFunc(String text) {
return "mock_" + text;
}
同样的,上述示例中的方法如需访问发起调用的原始被测对象,也可不使用
覆写任意类的静态方法
对于静态方法的BlackBox
类型中的静态方法secretBox()
,该方法签名为BlackBox secretBox()
,则
@MockMethod(targetClass = BlackBox.class)
private BlackBox secretBox() {
return new BlackBox("not_secret_box");
}
对于静态方法的null
。
覆写任意类的new 操作
在@MockContructor
注解。此时被测类中所有用new
创建指定类的操作(并使用了与
例如,在被测类中有一处new BlackBox("something")
调用,希望在测试时将它换掉(通常是换成
// 要覆写的构造函数签名为`BlackBox(String)`
// Mock方法返回`BlackBox`类型对象,方法的名称随意起
@MockContructor
private BlackBox createBlackBox(String text) {
return new BlackBox("mock_" + text);
}
在Mock 方法中区分调用来源
在
@Test
public void testDemo() {
MOCK_CONTEXT.put("case", "data-ready");
assertEquals(true, demo());
MOCK_CONTEXT.put("case", "has-error");
assertEquals(false, demo());
}
在
@MockMethod
private Data mockDemo() {
switch((String)MOCK_CONTEXT.get("case")) {
case "data-ready":
return new Data();
case "has-error":
throw new NetworkException();
default:
return null;
}
}