如何使用Powermock或mockito模拟类的"this"



我想模拟的类:

测试类.java

public class testClass(){
    public String getDescription(String input){
        String value = this.getDetails(input); // i am not going to change this line, hence want to mock this.
       //below this i have some complexity logic, which i would like to fix cyclomatic complexity issue            
    }
    private String getDetails(String input){
        return "More details for the "+input;
    }
}

我的问题是我如何模拟"this.getDetails(input)"以返回一些用于测试目的的字符串?

如果你有一个足够大和复杂的类,你需要模拟其中的一小部分,把它当作一个暗示,你违反了单一责任原则,并适当地划分类。如果使用依赖项注入,则可以提供所需的任何实现。

public class TestClass {
    /**
      * Computes a detail string based on an input. Supply this in the constructor
      * for full DI, relax visibility, or add a setter.
      */
    private final Function<String, String> detailFunction;
    public String getDescription(String input){
        String value = detailFunction.apply(input);
        // ...
    }
}

作为轻量级替代方案,您可以测试实际类的覆盖或间谍。

@Test public void testTestClassWithOverride() {
  TestClass instanceUnderTest = new TestClass() {
    @Override public String getDescription(String input) {
      return "Predictable value";
    }
  };
  // test your instanceUnderTest here
}
@Test public void testTestClassWithSpy() {
  TestClass spyUnderTest = Mockito.spy(new TestClass());
  doReturn("Predictable value").when(spyUnderTest).getDescription(anyString());
  // test your spyUnderTest here
}

请记住,虽然这是您的一个选项,但它不应该是您的第一个选择:您不是测试您的实际类,而是测试它的一次性变体,并且您已经做到了其他消费者也可以子类化您的 TestClass。如果可能,将您需要的灵活性写入类本身,并将您的测试视为遵循相同规则的使用者。

首先,制作所谓的"部分模拟"是一种不好的做法。这说明您的代码不遵循单一责任原则,从而导致您的代码无法(或很难)测试。

我建议你从你的类中提取getDescription方法,并通过依赖反转或更具体的依赖注入(例如通过使用 Spring 框架)间接使用它:

public class TestClass() {
    private DetailsServiceProvider detailsServiceProvider;
    public TestClass(DetailsServiceProvider detailsServiceProvider) {
        this.detailsServiceProvider = detailsServiceProvider;
    }
    public String getDescription(String input) {
        String value = detailsServiceProvider.getDetails(input); // i am not going to change this line, hence want to mock this.
       //below this i have some complexity logic, which i would like to fix cyclomatic complexity issue            
    }
}
public interface DetailsServiceProvider {
    String getDetails(String input);
}
public class DetailsServiceProviderImpl implements DetailsServiceProvider{
    @Override
    public String getDetails(String input) {
        return "More details for the "+input;
    }
}

然后在测试中,您可以简单地:

@Test 
public void test() {
  DetailsServiceProvider mockedProvider = Mockito.mock(DetailsServiceProvider.class);
  //TODO: add scenarios for the mocked object
  TestClass target = new TestClass(mockedProvider);
  String description = target.getDescription();
  //TODO: add assertions
}

如果您不想为首选方法而苦苦挣扎,则可以在Mockito中使用@Spy。这将创建您想要的 - 对象的部分模拟,其中部分方法将是真实的,另一部分 - 模拟:

@Test 
public void test() {
  TestClass partialMockedObject = Mockito.spy(new TestClass());
  Mockito.doReturn("test details").when(partialMockedObject).getDetails();
  String description = partialMockedObject.getDescription();
  //TODO: add assertions
}

同样,此方法不是必需的,但如果没有给出其他选项,则可以使用此方法。请注意,这要求getDetails()在测试中可见,这意味着private修饰符在此处不起作用。

相关内容

  • 没有找到相关文章

最新更新