有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用mock检查迭代期间是否分析了每个对象

我不知道如何使用mock来检查我的方法是否每次都被调用。我真的不知道如何描述这个问题,所以我将继续展示我的代码:

我有两个交互类:FilterFiltrable(接口)Filter类能够过滤可过滤项-它返回可过滤项(因此,如果需要,可以应用其他过滤器)。过滤方法只是迭代每个可过滤行,检查该行是否已过滤,然后将其添加到结果filtrable(若已过滤)。我想测试每个输入行是否都经过了真正的检查

下面是来自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);
}

这里的想法是使短截线可过滤,它由三条相同的虚线组成。然后将它们传递给过滤器类,并检查方法isLineFiltered是否每次使用相同的dummyLine调用三次

在阅读了Martin Fowler的Mocks Aren't Stubs之后,我明白这是完全错误的,因为我没有在任何地方测试实际的系统(Filter

那么,如何验证“测试中的系统”中的方法是否使用mock调用了三次?这是至关重要的,因为我正在努力学习这种方法。我可以很容易地创建一个从过滤器继承的测试类,计算调用isLineFiltered的次数,然后检查它。我只是觉得这可以用mock很好地完成

我在这里使用Mockito,如果有任何建议也使用它,那就太好了(当然,任何其他java模拟框架都可以)

附言

在我运行测试之后,将抛出来自MockitoWanted 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,所以这就是为什么最终的解决方案和我最初的尝试略有不同

谢谢你的帮助


共 (1) 个答案

  1. # 1 楼答案

    测试中的一个问题是,你没有真正测试你的过滤器类,因为你也被嘲笑了

    这个错误也是意料之中的。 您指定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);
            }
        }
    

    我是在脑子里想出来的,所以可能会有一些小错误