将 Mockito VerificationModes 与 JUnit 参数化测试结合起来?
Combine Mockito VerificationModes with JUnit Parameterized Tests?
起点
我想对 class 进行单元测试,它基本上不会自己创建输出,而是修改它接收到的对象。准确地说:它委托给一个服务 class,创建一个附加到对象 imageList
:
的图像
public class Class {
//field declarations ...
public Class(@Autowired Service service){
this.service = service;
}
public Object process(Object object){
//determine property here ...
if(property == optionA){
//the service will add the new image A to a list in object
this.service.createImageA(object);
} else if(property == optionB){
//the service will add the new image B to a list in object
this.service.createImageB(object);
}
//object will be returned, with or without a new image
return object;
}
}
到目前为止的工作
在我看来,最好的测试方法 class 是:
- 检查返回的产品是否与分配给
process
方法的产品相同
- 检查两个
service
方法被调用的频率(service
当然是用 Mockito 模拟的;))
现在我想将其与 JUnit 创建参数化测试的能力结合起来。类似于:
@Parameters
public static List<Object[]> parameters() {
return Arrays.asList(new Object[][] {
{optionA, Mockito.times(1), Mockito.never()},
{optionB, Mockito.never(), Mockito.times(1)},
{optionC, Mockito.never(), Mockito.never()},
});
}
问题
1. 是否可以在参数化测试中传递静态函数?
2.是否有特殊原因不这样做?
3. 任何已知的替代品?
提前致谢。
never
和 times
return VerificationMode implementations. Though you're right to be wary of the calling semantics, there seem to be no side effects to VerificationMode creation,所以你可以自由地将你的模式提取到一个变量中并传递它。
但是请注意,VerificationMode 实现可能是有状态的(我没有机会深入挖掘),因此重用实例可能会导致奇怪的错误。
正如上面提到的 Florian Schaetz,您可以改为选择传递整数:never
只是 times(0)
的别名,因此您可以将预期的调用次数(0 或 1)传递为一个 JUnit 参数,然后在您的测试中调用 times(parameter)
,而不必担心状态或副作用。
从 Java 8 开始,您 可以 使用 method references or lambda expressions 在函数之间将代码作为数据传递 ,但结果可能不容易阅读或维护,尤其是在 Object[]
:
中保留方法引用所需的强制转换
@RunWith(Parameterized.class)
public class LambdaParameters {
public static Integer toot() { return 0; }
public static Integer whistle() { return 1; }
public static Integer plunk() { return 2; }
public static Integer boom() { return 3; }
private static Supplier<Integer> wrap(Supplier<Integer> methodCall) {
return methodCall;
}
@Parameters public static List<Object[]> parameters() {
return ImmutableList.of(
// Java 8 knows that static call "toot" is effectively a Supplier<Integer>...
new Object[] { (Supplier<Integer>) LambdaParameters::toot, 0 },
// ...but it won't infer that without the cast...
new Object[] { (Supplier<Integer>) LambdaParameters::whistle, 1 },
// ...or without getting the hint through a method like "wrap" above.
new Object[] { wrap(LambdaParameters::plunk), 2 },
// Most lambda expressions are for calling Runnables, Listeners, Callbacks,
// and short Functions or Predicates, so the casts there aren't necesssary.
// You can use this syntax for compact lambda functions too.
new Object[] { wrap(() -> 3), 3 },
// All of these are effectively anonymous inner classes as you might see
// in previous versions of Java.
new Object[] { new Supplier<Integer>() { @Override public Integer get() { return LambdaParameters.boom(); }}, 3 }
);
}
private Supplier<Integer> supplier;
private Integer integer;
public LambdaParameters(Supplier<Integer> supplier, Integer integer) {
this.supplier = supplier;
this.integer = integer;
}
@Test public void supplierSuppliesExpectedInteger() {
assertEquals(integer, supplier.get());
}
}
这是否值得额外的逻辑完全取决于你有多少参数,你有多少测试,以及是否有任何替代方案(就像 VerificationMode 一样)。
起点
我想对 class 进行单元测试,它基本上不会自己创建输出,而是修改它接收到的对象。准确地说:它委托给一个服务 class,创建一个附加到对象 imageList
:
public class Class {
//field declarations ...
public Class(@Autowired Service service){
this.service = service;
}
public Object process(Object object){
//determine property here ...
if(property == optionA){
//the service will add the new image A to a list in object
this.service.createImageA(object);
} else if(property == optionB){
//the service will add the new image B to a list in object
this.service.createImageB(object);
}
//object will be returned, with or without a new image
return object;
}
}
到目前为止的工作
在我看来,最好的测试方法 class 是:
- 检查返回的产品是否与分配给
process
方法的产品相同 - 检查两个
service
方法被调用的频率(service
当然是用 Mockito 模拟的;))
现在我想将其与 JUnit 创建参数化测试的能力结合起来。类似于:
@Parameters
public static List<Object[]> parameters() {
return Arrays.asList(new Object[][] {
{optionA, Mockito.times(1), Mockito.never()},
{optionB, Mockito.never(), Mockito.times(1)},
{optionC, Mockito.never(), Mockito.never()},
});
}
问题
1. 是否可以在参数化测试中传递静态函数?
2.是否有特殊原因不这样做?
3. 任何已知的替代品?
提前致谢。
never
和 times
return VerificationMode implementations. Though you're right to be wary of the calling semantics, there seem to be no side effects to VerificationMode creation,所以你可以自由地将你的模式提取到一个变量中并传递它。
但是请注意,VerificationMode 实现可能是有状态的(我没有机会深入挖掘),因此重用实例可能会导致奇怪的错误。
正如上面提到的 Florian Schaetz,您可以改为选择传递整数:never
只是 times(0)
的别名,因此您可以将预期的调用次数(0 或 1)传递为一个 JUnit 参数,然后在您的测试中调用 times(parameter)
,而不必担心状态或副作用。
从 Java 8 开始,您 可以 使用 method references or lambda expressions 在函数之间将代码作为数据传递 ,但结果可能不容易阅读或维护,尤其是在 Object[]
:
@RunWith(Parameterized.class)
public class LambdaParameters {
public static Integer toot() { return 0; }
public static Integer whistle() { return 1; }
public static Integer plunk() { return 2; }
public static Integer boom() { return 3; }
private static Supplier<Integer> wrap(Supplier<Integer> methodCall) {
return methodCall;
}
@Parameters public static List<Object[]> parameters() {
return ImmutableList.of(
// Java 8 knows that static call "toot" is effectively a Supplier<Integer>...
new Object[] { (Supplier<Integer>) LambdaParameters::toot, 0 },
// ...but it won't infer that without the cast...
new Object[] { (Supplier<Integer>) LambdaParameters::whistle, 1 },
// ...or without getting the hint through a method like "wrap" above.
new Object[] { wrap(LambdaParameters::plunk), 2 },
// Most lambda expressions are for calling Runnables, Listeners, Callbacks,
// and short Functions or Predicates, so the casts there aren't necesssary.
// You can use this syntax for compact lambda functions too.
new Object[] { wrap(() -> 3), 3 },
// All of these are effectively anonymous inner classes as you might see
// in previous versions of Java.
new Object[] { new Supplier<Integer>() { @Override public Integer get() { return LambdaParameters.boom(); }}, 3 }
);
}
private Supplier<Integer> supplier;
private Integer integer;
public LambdaParameters(Supplier<Integer> supplier, Integer integer) {
this.supplier = supplier;
this.integer = integer;
}
@Test public void supplierSuppliesExpectedInteger() {
assertEquals(integer, supplier.get());
}
}
这是否值得额外的逻辑完全取决于你有多少参数,你有多少测试,以及是否有任何替代方案(就像 VerificationMode 一样)。