【问题标题】:How to run a unit test using the SpringBoot 2如何使用 Spring Boot 2 运行单元测试
【发布时间】:2020-07-28 22:35:55
【问题描述】:

我有以下测试:

@SpringBootTest
@ExtendWith(SpringExtension.class)
class BookServiceImplTest {
    @MockBean
    private BookRepository bookRepository;
    @MockBean
    private LibraryService libraryService;

    @Autowired
    private BookServiceImpl bookService;

    @Test
    void create() {
        BookRequestDTO bookRequestDTO = new BookRequestDTO();
        Library library = new Library();
        Book expectedBook = new Book();
        when(libraryService.getById(bookRequestDTO.getLibraryId()))
                .thenReturn(library);
        when(bookRepository.save(any(Book.class)))
                .thenReturn(expectedBook);

        Book actualBook = bookService.create(bookRequestDTO);

        assertEquals(expectedBook, actualBook);
    }
}

没关系,它可以运行,但我想知道有没有办法将它作为单元测试而不是集成测试运行,并且仍然使用@MockBean @Autowired。还是我遗漏了什么?

我尝试只留下 @ExtendWith(SpringExtension.class),但我得到一个关于未找到 BookServiceImpl bean 的异常。

我知道如何使用 MockitoExtension 和 @Mock、@InjectMocks 来做到这一点,但我想知道是否有更多的 SpringBoot 方式来做到这一点?

【问题讨论】:

  • 我认为您没有这样的可选选项,请使用 @SpringBootTest@ContextConfiguration

标签: java spring spring-boot junit junit5


【解决方案1】:

您可以通过四个步骤对其进行单元测试:

  • 删除 @SpringBootTest 注释,因为它正在启动整个 Spring 上下文 ― 对于模拟所有协作者的单元测试没有用处
  • BookServiceImpl 声明中删除 @Autowired 注释并添加一个 @BeforeEach 设置方法,在该方法中初始化 bookService 并传递 bookRepositorylibraryService 作为参数
  • 在 ExtendWith 注释中使用 MockitoExtension 而不是 SpringExtension。在这里,我假设您可以使用像 Mockito 这样的库来模拟您的合作者
  • 使用 Mockito 的 @Mock 而不是 @MockBean,因为我们正在手动初始化 bookService,因此无需处理 Spring bean

在您的第一个问题上添加更多内容:@Mockbean@Autowired 是对集成测试有意义的注释,因为它们处理 bean 的模拟和注入。单元测试应该孤立地考虑这个类,模拟与其他类的交互,因此不需要启动应用程序上下文并设置 bean。

【讨论】:

    【解决方案2】:
    1. 删除@SpringBootTest,这将加载整个上下文并减慢您的测试速度。 @MockBean 的作用是从指定的 bean 创建一个 mock 并将其添加到上下文中。由于没有上下文运行,使用@MockBean

    2. 没有意义
    3. @RunWith(SpringRunner.class)注释你的单元测试类

    4. 对于注入依赖项,这是一个很好的做法,即显式地创建配置文件和模拟 bean 并使用它们创建目标 bean。假设您使用的是基于构造函数的注入:

      @Profile("test")
      @Configuration
      public class BookServiceTestConfiguration {
      
      
          @Bean
          public BookRepository bookRepository() {
              return Mockito.mock(BookRepository.class);
          }
      
          @Bean
          public LibraryService libraryService() {
              return Mockito.mock(LibraryService.class);
          }
      
          @Bean
          public BookService bookService() {
             BookServiceImpl bookService = new BookServiceImpl(
                      bookRepository(), libraryService()
              );
      
             return userGroupService;
          }
      }
      

    然后将你的测试类写成:

        @ActiveProfiles("test")
        @Import(BookServiceTestConfiguration .class)
        @RunWith(SpringRunner.class)
        public class BookServiceUnitTest {
    
            @Autowired
            private BookService bookService;
    
            // write unit tests
        }
    
    1. 更多信息,请阅读this article

    【讨论】:

    • ˋ @RunWith(SpringRunner.class)ˋ 仅在您没有本机 JUnit 5 支持时才需要。它将使用 JUnit 4 运行 JUnit 5 测试。这里不需要。
    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 2017-10-21
    • 2016-12-07
    • 2016-12-22
    • 2020-07-09
    • 2015-11-05
    相关资源
    最近更新 更多