我不知道如何使用mock来检查我的方法是否在每次应该调用时都被调用。我真的不知道如何描述这个问题,所以我会继续展示我的代码:
我有两个交互类:Filter
和Filtrable
(一个接口)。Filter
类能够过滤可过滤项-返回可过滤项(因此,如果需要,可以应用其他过滤器)。过滤方法只是迭代每个可过滤的行,检查该行是否被过滤,然后添加到可过滤的结果中。我想测试每个输入行是否真的被检查过。
这是Filter
类的代码:
public Filtrable filter(Filtrable input) {
Filtrable result = input.createEmptyFiltrable();
while(input.hasNextLine()){
Line line = input.nextLine();
if(isLineFiltered(line)){
result.addLine(line);
}
}
return result;
}
这是我(失败的)测试它的尝试:
@Test
public void testFilter(){
Filtrable mockedFiltrable = mock(Filtrable.class);
when(mockedFiltrable.createEmptyFiltrable()).thenReturn(new StringArrayFiltrable());
when(mockedFiltrable.hasNextLine()).thenReturn(true,true,true,false);
when(mockedFiltrable.nextLine()).thenReturn(dummyLine);
Filter mockedFilter = mock(Filter.class);
mockedFilter.filter(mockedFiltrable);
verify(mockedFilter, times(3)).isLineFiltered(dummyLine);
}
这里的想法是制作一个存根可过滤的,它由三条相同的伪线组成。然后将它们传递给Filter类,并检查方法isLineFiltered
是否每次都用相同的dummyLine调用了三次。
在阅读了马丁·福勒的《Mocks Aren Not Stubs》之后,我明白这是完全错误的,因为我没有在任何地方测试实际的系统(Filter
)!
那么我如何验证";"System Under Test";使用mock调用了三次?这是至关重要的,因为我正在努力学习这种方法。我可以很容易地创建一个从Filter继承的测试类,计算isLineFiltered
被调用的次数,然后检查它。我只是觉得用mock可以很好地做到这一点。
我在这里使用Mockito,如果有任何建议也使用它,那就太好了(但任何其他java嘲讽框架都可以)。
第页。S.
在我运行测试之后,Mockito Wanted but not invoked: filter.isLineFiltered
抛出了一个异常。
编辑:
可过滤接口如下:
public interface Filtrable {
public Filtrable createEmptyFiltrable();
public boolean hasNextLine();
public void addLine(Line line);
public Line nextLine() throws FiltrableException;
}
解决方案:
以下是我最终的做法:
@Test
public void testFilter(){
Filtrable mockedFiltrable = mock(Filtrable.class);
Filtrable mockedFiltrableResult = mock(Filtrable.class);
when(mockedFiltrable.createEmptyFiltrable()).thenReturn(mockedFiltrableResult);
Iterator<Line> mockedIterator = mock(Iterator.class);
when(mockedFiltrable.iterator()).thenReturn(mockedIterator);
when(mockedIterator.hasNext()).thenReturn(true,true,true,false);
when(mockedIterator.next()).thenReturn(dummyLine);
Filter filterUnderTest = new TestFilter(true);
filterUnderTest.filter(mockedFiltrable);
verify(mockedFiltrableResult,times(3)).addLine(dummyLine);
}
我已经更改了Filtrable接口来扩展Iterable,所以这就是为什么最终的解决方案和我最初的尝试有点不同。
谢谢你的帮助!
测试的一个问题是,您实际上并没有测试过滤器类,因为您也受到了嘲笑。
错误也是意料之中的事。您指定要调用isLineFiltered
三次,但也模拟了测试中的类。这会导致filter方法也被模拟,因此不会调用isLineFilter
方法。
如何使用模拟测试的一个简单示例:
@Controller
public class KajmanController {
@Autowired
private KajmanInfoService kajmanInfoService;
@RequestMapping(method = RequestMethod.GET)
public String getInfo(@RequestParam(value="myParam[]") String[] myParams){
//some logic
for (String param : myParams) {
Info info = kajmanInfoService.getInfo(param);
//some logic
}
//some logic
}
}
那么,您唯一需要模拟的就是kajmanInfoService。
因此,你的测试可以大致如下:
@RunWith(MockitoJUnitRunner.class)
public class KajmanControllerTest {
@Mock
private KajmanInfoService kajmanInfoService ;
@InjectMocks
private KajmanController controller;
@Test
public void customerInfoRetrieved() {
//some logic
when(kajmanInfoService.getInfo(anyString()).thenReturn(expectedInfo);
//some logic
String[] expectedInfoArguments = {"A1","B1","C1"};
controller.getInfo(expectedInfoArguments);
verify(kajmanInfoService, times(3)).getInfo(anyString);
}
}
我做这件事是出于我的考虑,所以它可能包含一些小错误。