有 Java 编程相关的问题?

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

java如何使用SpringBoot 2运行单元测试

我有以下测试:

@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),但我得到了一个关于bookserviceimplbean的异常,没有找到

我知道如何使用MockitoExtension和@Mock、@InjectMocks来实现这一点,但我想知道是否有一种更好的SpringBoot方式来实现这一点


共 (2) 个答案

  1. # 1 楼答案

    1. 删除@SpringBootTest,这将加载整个上下文并降低测试速度。@MockBean的作用是从指定的bean创建一个模拟,并将其添加到上下文中。因为没有上下文运行,所以使用@MockBean

    2. @RunWith(SpringRunner.class)

    3. 对于注入依赖项,显式地创建配置文件和模拟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
  2. # 2 楼答案

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

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

    在第一个问题上再补充一点:@Mockbean@Autowired是对集成测试有意义的注释,因为它们处理bean的模拟和注入。单元测试应该孤立地考虑这个类,嘲笑与其他类的交互,因此不需要旋转应用程序上下文并设置bean。p>