Spring Boot 测试中使用 Mockito 验证方法调用次数

3

我想验证一个被模拟的方法 (fileSenderService.sendFile) 被调用了恰好2次。但无论期望的调用次数是多少,Mockito 都没有引发测试失败。我是这样使用它的:

verify(mockService, times(expectedNumberOfInvocations)).sendFile(any(String.class), any(byte[].class));

无论在 times() 方法中使用什么值,测试总是通过。

MyService 的代码看起来像这样:

@Service
public class MyServiceImpl implements MyService {

    @Autowired
    private FileSenderService fileSenderService;

    public void createAndSendFiles(){
        //doSomeStuff, prepare fileNames and fileContents(byte arrays)
        //execute the sendFile twice
        fileSenderService.sendFile(aFileName, aByteArray); //void method; mocked for testing
        fileSenderService.sendFile(bFileName, bByteArray); //void method; mocked for testing
    }

测试类

@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = {Application.class, FileSenderServiceMock.class})
@ContextConfiguration
public class MyServiceTest{

    @Autowired
    private MyService myService;

    @Autowired
    FileSenderService mock;

    @Test
    public void shouldCreateAndSendFiles(){
        myService.createAndSendFiles(); //inside this method sendFile() is called twice
        verify(mock, times(999)).sendFile(any(String.class), any(byte[].class)); //THE PROBLEM - why times(999) does not fail the test?
    }
}


文件发送服务及其模拟:
@Service
public class FileSenderServiceImpl implements FileSenderService {
   @Override
    public void sendFile(String name, byte [] content) {
      //send the file
    }
}

//used for testing instead of the actual FileSenderServiceImpl 
public class FileSenderServiceMock {
    @Bean
    @Primary
    public FileSenderService getFileSenderServiceMock(){
        FileSenderServicemock = Mockito.mock(FileSenderService.class, Mockito.RETURNS_DEEP_STUBS);

        doNothing().when(mock).sendFile(isA(String.class), isA(byte[].class));
        return mock;
    }

如果您正在测试MyService,不应该使用Autowire注入FileSenderService,而应该使用@Mock注解进行模拟。在测试代码中,在调用myService.createAndSendFiles()之前添加“doNothing()…”行。 - ruba
1个回答

0

如果您在使用@SpringBootTest进行集成测试时,无需为模拟定义任何测试配置类,只需使用@MockBean注释将模拟注入到测试上下文中即可。

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceTest{

    @Autowired
    private MyService myService;

    @MockBean
    FileSenderService fileSenderService;

    @Test
    public void shouldCreateAndSendFiles(){
    myService.createAndSendFiles(); 
    verify(fileSenderService, times(2)).sendFile(any(String.class), any(byte[].class));
   }
}

嗨,使用MockBean的效果如预期。但是我想将模拟对象放在一个单独的文件中,以便可以在多个测试之间共享(mocked service实际上包含多个方法,因此在每个测试类中键入"when(mock).someMethod.thenReturn(something)"很耗时。 - Domin0
如果您展示所有代码,例如“verify”方法来自哪个包,那将非常有用,因为大多数IDE无法确定静态方法的导入。 - Francisco Fiuza
大部分答案对我来说都有效,但是当我使用@MockBean时,验证仍然无法工作。值得注意的是,我正在使用Junit 5,而不是你在这里所做的Junit 4。您是否有任何信息,关于是否需要一些特定的配置来启用验证? - Lewis_McReu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接