如何模仿"这个"使用powermock或mockito的课程

时间:2017-10-31 15:45:54

标签: junit mockito this powermock

我想要模拟的类:

TestClass.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(输入)"返回一些字符串用于测试目的?

2 个答案:

答案 0 :(得分:1)

如果你有一个足够大且足够复杂的课程,你需要嘲笑它的一小部分,那么请将其作为你违反Single Responsibility Principle并正确拆分的提示上课。如果您使用依赖注入,则可以提供您喜欢的任何实现。

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
}

请记住,虽然这是一个适合您的选择,但它不应该是您的第一选择:您不是测试您的实际课程,而是测试它的一次性变体,而您和&# #39; ve使它成为其他消费者也可以继承你的TestClass。如果可能,将您需要的灵活性写入类本身,并将您的测试视为按照相同规则播放的消费者。

答案 1 :(得分:1)

首先,做一个所谓的&#34;局部模拟&#34;是一种不好的做法。这说明您的代码不遵循单一责任原则,导致您的代码无法(或几乎)无法测试。

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

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修饰符不会在这里工作。