当前位置: 首页 > 知识库问答 >
问题:

与单元测试控制器和服务方法的差异[重复]

范志勇
2023-03-14

我想从控制器和服务层测试相同的方法。问题是:为什么我必须在控制器中使用@MockBean注释,为什么不为BookFindOperationsService bookService使用@Mock注释。对于服务,同样的问题是,为什么我需要@Mock存储库,为什么不使用@MockBean?你能告诉我这两者的区别吗?

这里是控制器:

@RestController
public class BookFindOperationsController {

    private final BookFindOperationsService bookService;

    @Autowired
    public BookFindOperationsController(BookFindOperationsService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/books/author/{authorID}")
    public List<Book> findBooksByAuthor(@PathVariable String authorID) {
        return bookService.findBooksByAuthor(authorID);
    }

}

这里是服务类:

@Service
public class BookFindOperationsService {
    private final BookRepository bookRepository;

    @Autowired
    public BookFindOperationsService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    public List<Book> findBooksByAuthor(String authorID) {
        return bookRepository.findByAuthorAllIgnoreCase(authorID);
    }
}

服务测试:

@RunWith(MockitoJUnitRunner.class)
public class BookFindOperationsServiceTest {

    @Mock
    BookRepository bookRepository;

    @InjectMocks
    BookFindOperationsService bookFindOperationsService;

    @Test
    public void findBooksByAuthor() {
        Book book = createDummyBook();
        List<Book> books = new ArrayList<>();
        books.add(book);

        when(bookRepository.findByAuthorAllIgnoreCase("Henryk Sienkiewicz")).thenReturn(books);

        assertEquals(1, bookFindOperationsService.findBooksByAuthor("Henryk Sienkiewicz").size());
    }

private Book createDummyBook() {
        return new Book("W pustyni i w puszczy", "Henryk Sienkiewicz", "dramat", true);
    }

控制器测试:

@RunWith(SpringRunner.class)
@WebMvcTest(BookFindOperationsController.class)
public class BookFindOperationsControllerTest {
    @Autowired
    MockMvc mockMvc;

    @MockBean
    BookFindOperationsService bookService;

    @Test
    public void findBooksByAuthor() throws Exception {
        List<Book> books = new ArrayList<>();
        Book book = new Book("W pustyni i w puszczy", "Henryk Sienkiewicz", "dramat", true);
        books.add(book);

        when(bookService.findBooksByAuthor("Henryk Sienkiewicz")).thenReturn(books);

        String expected = "[{\"id\":0,\"title\":\"W pustyni i w puszczy\",\"author\":\"Henryk Sienkiewicz\",\"category\":\"dramat\",\"available\":true}]";

        MvcResult mvcResult = mockMvc.perform(get("/books/author/Henryk Sienkiewicz")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andReturn();

        String content = mvcResult.getResponse().getContentAsString();

        assertEquals(expected, content);

        verify(bookService, times(1)).findBooksByAuthor(anyString());
    }

共有2个答案

夹谷弘亮
2023-03-14

@MockBean用于向Spring应用程序上下文添加mock对象。模拟将替换应用程序上下文中任何现有的相同类型的bean。你可以在集成测试中使用它

@moock在单元测试中用于替换某些实现。看这儿

使用@MockBean时的一个重要注意事项。在这种情况下,Spring上下文不会缓存,如果您有许多集成测试,上下文的初始化可能会花费大量时间。

权弘新
2023-03-14

@Mock@MockBean之间的主要区别在于前者属于Mockito框架,后者属于Mockito下的Spring测试框架。

@MockBean用模拟Bean创建/替换Spring Bean,以便其他Spring加载的Bean(控制器等)可以使用它。这就是为什么在使用MockMvc时需要它。执行

@Mock注释不适用于Spring上下文。它只会尝试将标记有此注释的模拟对象映射到标记有@InjectMocks的对象的属性。

更新

当使用@WebMvcTest(BookFindOperationsController.class)时,将创建一个Spring上下文,该上下文包含所有必要的bean,以支持作为Web应用程序运行BookFindOperationsController类。这意味着任何拦截器、过滤器、转换器也需要在Spring上下文中加载。这个Spring上下文还将加载自己的BookFindOperationsService,它不是一个模拟的,而是一个实际的实现。但是为了进行测试,你需要一个Mock,这就是为什么你用@MockBean注释这个bean,以指示Spring上下文使用模拟的bean而不是实际的bean。这是一个集成测试,因为您可以测试所有组件是否正确地协同工作。

使用@RunWith(MockitoJUnitRunner.class)时,不会隐式创建任何Spring上下文。因此,您不能使用@MockBean,因为没有可模拟的Spring bean。这是一个单元测试,因为您在模拟BookRepository时只测试BookFindOperationsService,而没有实际在数据库中保存任何内容。

希望这能解释清楚。

 类似资料:
  • 问题内容: 我有以下情况: controller.js controllerSpec.js 错误: 我也尝试过类似的方法,但没有成功: 我该如何解决?有什么建议? 问题答案: 有两种方法(或肯定有更多方法)。 想象一下这种服务(无论它是工厂都没关系): 使用此控制器: 一种方法是使用要使用的方法创建对象并对其进行监视: 然后,将其作为dep传递给控制器​​。无需注入服务。那可行。 另一种方法是模拟

  • 我已经开始考虑在我的项目中围绕一些业务逻辑添加一些单元测试。 我想测试的第一个方法是服务层中的一个方法,它返回给定节点的子节点列表。 该方法如下所示: 我想象这样的测试方法是提供一个假树结构,然后测试提供节点是否返回正确的子节点。 ssdsContext是一个对象上下文。 我已经看到可以为提取和接口如何模拟ObjectContext或ObjectQuery 我还读到,as Entity Frame

  • 本文向大家介绍AngularJS 单元测试控制器,包括了AngularJS 单元测试控制器的使用技巧和注意事项,需要的朋友参考一下 示例 控制器代码: 考试: 跑!

  • 好的,我试过了。但我不能把我的头缠在这上面。 我有控制器 Svc是ExtController抽象类中的服务类型的公共属性,它反过来扩展Controller类 下面是使用NUnit的单元测试代码 问题是,当调用Create方法时,它需要使用Svc来处理操作,所以我想我必须嘲笑它!但我不知道怎么做。 我应该嘲笑控制器吗!但我不能,因为它是一个密封的类!或者是ExtController!我迷路了,需要指

  • 如何为GraphQL编写单元测试?我正在使用apollo服务器、graphql-tester和graphql。

  • 问题内容: 我有一个ParseService,我想对其进行模拟以测试使用它的所有控制器,我一直在阅读有关茉莉花间谍的信息,但对我来说仍然不清楚。谁能给我一个关于如何模拟定制服务并在Controller测试中使用它的示例吗? 现在,我有一个使用服务插入书的控制器: 服务是这样的: 到目前为止,我的测试如下所示: 现在测试失败: 我做错了什么? 问题答案: 我做错的是没有在beforeEach中将模拟