使用 Mockito 模拟任何方法签名 [英] Mock any method signature with Mockito

查看:77
本文介绍了使用 Mockito 模拟任何方法签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一段设计得不是很好的代码,但我不是这段代码的所有者,所以我无法更改它.

Hi I have this piece of code that is not very well designed, but I'm not the owner of this code so I can't change it.

public interface Car{ // This is a marker interface. }

public class BigCar implements Car{ 
  public boolean isVeryBig(){ 
  return true;}
} 

public class QuiteBigCar implements Car{ 
  public boolean isVeryBig(boolean withHatchBack){ 
  return true;}
}   

public Pickup implements Car{ 
  public boolean isVeryBig(boolean withHatchBack, boolean withRoofRack){ 
  return true;}
}

你看到这个界面只是为了让我知道BigCarQuiteBigCarPickup是一辆"汽车.不是很聪明,但这就是我必须处理的.

You see the interface only exists to let me know that BigCar, QuiteBigCar and Pickup "is a" Car. Not very clever, but that's what I have to deal with.

现在我有一个方法可以接收汽车作为参数,并返回汽车的模拟版本.我希望模拟确保每次 isVeryBig() 被调用时,它都会返回 false 不管方法签名如何.问题是我没有所有 isVeryBig() 方法的通用接口;他们都有不同的签名.

Now I have a method that receives a Car as a param and will returned a mocked version of the car. I want the mock to make sure every time isVeryBig() is called, it will return false regardless of the method signature. The problem is I don't have a common interface for all isVeryBig() methods; they all have a different signature.

public Car mockMyCar(Car car){

     Car mockedCar = mock(car);

     when(mockedCar.isVeryBig())  <-- This wont work since the method doesn't exist on the interface

    return mockedCar;
}

是的,我可以将 Car 转换为它们的子类,但这对我来说不是一个选项,因为实现 Car 的类太多了,对所有实现进行 instanceOf 检查会使代码非常讨厌,而且我无法控制 newCar 在未来的实现.

Yes, I could cast Car into their subclass but this is not an option for me as there is too many classes that implement Car, make a instanceOf check on all implementation would make the code very nasty and I don't control new implementations of Car in the future.

有什么想法吗?

推荐答案

一些选项,从最不友好到最不友好:

A few options, in order from least-hacky to most-hacky:

  • 承认在这里模拟 Car 与模拟 Serializable 一样没有意义,并且您实际上应该选择一个实现来模拟.您不会在模拟具体的 BigCar 或 Pickup 时遇到同样的麻烦,并且您可以在几个测试用例中运行几个不同的实现.

  • Acknowledge that mocking a Car here makes as little sense as mocking a Serializable, and that you should actually pick an implementation to mock. You won't have the same trouble mocking a concrete BigCar or Pickup, and you can run through a few different implementations in a few test cases.

重构为 TrustNoOne 描述的通用正确多态接口,而不是像这里那样使用替代多态.我知道您可能会束手无策,但接下来遇到这个问题的人可能不会.

Refactor to a common properly-polymorphic interface as TrustNoOne described, rather than using ersatz polymorphism the way you have here. I know you may have your hands tied, but whoever stumbles across this question next might not.

您可以通过 在创建模拟时提供默认答案:

Car car = Mockito.mock(Car.class, new Answer<Object>() {
  @Override public Object answer(InvocationOnMock invocation) {
    if (invocation.getMethod().getName().equals("isVeryBig")) {
      return false;
    }
    // Delegate to the default answer.
    return Mockito.RETURNS_DEFAULTS.answer(invocation);
  }
};

但是请记住,您的特定情况(能够向下转换为具有不同签名的各种实现之一)可能需要使用 extraInterfaces 特性让 Java 根据需要向下转换,这使得整个事情变得棘手和脆弱.您最好改用上述其他解决方案之一.

Bear in mind, though, that your particular situation (of being able to downcast to one of a variety of implementations with different signatures) may require use of the extraInterfaces feature to let Java downcast as needed, which makes this entire thing tricky and fragile. You'd probably be better off using one of the other above solutions instead.

这篇关于使用 Mockito 模拟任何方法签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆