使用Mockito模拟任何方法签名



嗨,我有一段代码设计得不太好,但我不是这段代码的所有者,所以我不能更改它。

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"是一辆"汽车。不是很聪明,但这正是我必须面对的。

现在我有一个方法,它接收一个Car作为参数,并返回一个模拟版本的汽车。我希望mock确保每次调用isVeryBig()时,无论方法签名是什么,它都会返回false。问题是我没有一个适用于所有isVeryBig()方法的通用接口;他们都有不同的签名。

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检查会使代码非常糟糕,而且我将来不会控制Car的新实现。

知道吗?

几个选项,按照从最不熟练到最熟练的顺序:

  • 承认在这里嘲笑Car和嘲笑Serializable一样没有什么意义,并且您实际上应该选择一个要嘲笑的实现。您不会在嘲笑具体的BigCar或皮卡时遇到同样的问题,并且您可以在几个测试用例中运行几个不同的实现。

  • 正如TrustNoOne所描述的那样,重构到一个通用的适当多态接口,而不是像这里那样使用伪多态。我知道你可能会束手束脚,但接下来遇到这个问题的人可能不会。

  • 通过在创建mock:时提供默认的Answer,您可以做一些类似于您所描述的事情——通过名称而不是签名来匹配方法

    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根据需要向下转换,这使得整个过程变得棘手和脆弱。您最好使用上述其他解决方案之一。

相关内容

  • 没有找到相关文章

最新更新