即使在模拟之后,Null 也会传递给自动装配服务 - SpringBootTest

Null is passed to autowired service even after mocking - SpringBootTest

我想对我的 API 进行集成测试。

@RestController
@RequestMapping("/api/v1")
public class TestController {

    @Autowired
    TestService testService;

    @RequestMapping("/welcome")
    public String welcomeMessage(@RequestParam("name") String name) {
        return testService.welcomeMessage(name);
    }
}

以下是服务接口及其实现:

public interface TestService {
    public String welcomeMessage(String name);
}

public class TestServiceImpl implements TestService{
    @Autowired
    TestRepository repo;

    @Override
    public String welcomeMessage(String name) {
        repo.save(new StringEntity(name));
        return "Hello "+name;
    }
}

下面是测试用例:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockitoTestingApplicationTests {

    @Autowired
    MockMvc mvc;

    @MockBean
    TestService testService;

    @MockBean
    TestController testController;

    @Test
    public void contextLoads() throws Exception {
        Mockito.when(testController.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();
        Mockito.when(testService.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod();

        mvc.perform(get("/api/v1/welcome").param("name", "dude")).andExpect(status().isOk());
    }

}

我有几个问题。

  1. 当我执行上面的代码时,它抛出一个错误,说不能在抽象方法上调用真实方法。当我嘲笑 TestServiceImpl 时,它会在控制器中抛出 NullPointerException,因为 TestService 为空。我该如何解决?

  2. 当我们使用 MongoDB 时,我应该如何模拟存储库层。当我尝试模拟 MongoTemplate 时,它抛出一个错误 MongoConvertor must not be null

  3. 这样写测试用例对吗?我们可以在不使用 thenCallRealMethod() 的情况下进行代码覆盖吗?

请建议我如何进行。提前致谢。

确保你有一个服务的实现,即 TestServiceImpl@Service 注释(或者 @Component 如果它不是严格的服务)并使用间谍而不是模拟:

@SpyBean
TestService testService;

间谍默认调用真实的方法,因此您必须模拟这些您不想调用的实现。

关于存储库,您应该模拟用 @Repository 注释的组件,而不是其中使用的实际 SessionFactory / Template 等。