我想要模拟的类:
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(输入)"返回一些字符串用于测试目的?
答案 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
修饰符不会在这里工作。