将Mockito VerificationModes与JUnit参数化测试相结合?

时间:2015-09-01 15:47:45

标签: java unit-testing junit mockito

起点
我想对一个基本上没有创建输出的类进行单元测试,但是修改它接收的对象。确切地说:它委托给一个服务类,它创建一个附加到对象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;
 }
}

迄今为止的工作
在我看来,测试这门课程的最好方法是:

  1. 检查返回的产品是否与分配给process方法的产品相同
  2. 检查调用两个service方法的频率(service当然是用Mockito嘲笑的;))
  3. 现在我想将此与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.任何已知的替代品?

    提前致谢。

1 个答案:

答案 0 :(得分:2)

nevertimes返回VerificationMode次实施。虽然您对调用语义保持警惕是正确的,但似乎有no side effects to VerificationMode creation,因此您可以自由地将模式提取到变量并将其传入。

请注意,VerificationMode实现可能是有状态的(我没有机会深入挖掘),因此重用实例可能会导致奇怪的错误。

正如上面提到的Florian Schaetz,您可以选择传递整数:never只是times(0)的别名,因此您可以将预期的调用次数(0或1)作为JUnit传递参数,然后在测试中调用times(parameter),而不必担心状态或副作用。

从Java 8开始,您可以使用method referenceslambda 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)。