如何 运行 使用 Spring Boot 2 进行单元测试
How to run a unit test using the 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);
}
}
没关系,它 运行s,但我想知道有没有办法 运行 将其作为单元测试而不是集成测试,并且仍然使用 @MockBean @Autowired。还是我漏掉了什么?
我试着只留下@ExtendWith(SpringExtension.class),但我得到一个关于未找到 BookServiceImpl bean 的异常。
我知道如何使用 MockitoExtension 和@Mock、@InjectMocks 来做到这一点,但我想知道是否有更多的 SpringBoot 方法来做到这一点?
删除 @SpringBootTest
,这将加载整个上下文并减慢您的测试速度。 @MockBean
的作用是从指定的bean 中创建一个mock 并将其添加到上下文中。由于没有上下文 运行,因此没有必要使用 @MockBean
用@RunWith(SpringRunner.class)
注释你的单元测试class
对于注入依赖项,这是一个很好的做法,可以显式创建配置文件和模拟 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;
}
}
然后将你的测试class写成:
@ActiveProfiles("test")
@Import(BookServiceTestConfiguration .class)
@RunWith(SpringRunner.class)
public class BookServiceUnitTest {
@Autowired
private BookService bookService;
// write unit tests
}
- 有关更多信息,请阅读 this article
您可以通过四个步骤对其进行单元测试:
- 删除
@SpringBootTest
注释,因为它正在旋转整个 Spring 上下文——对所有协作者都被模拟的单元测试没有用
- 从 BookServiceImpl 声明中删除
@Autowired
注释并添加一个 @BeforeEach
设置方法,在其中初始化 bookService
传递 bookRepository
和libraryService
作为参数
- 在 ExtendWith 注释中使用
MockitoExtension
而不是 SpringExtension
。在这里,我假设您能够使用像 Mockito 这样的库来模拟您的合作者
- 使用 Mockito 的
@Mock
而不是 @MockBean
,因为我们是手动初始化 bookService
所以不需要处理 Spring 个 beans
关于您的第一个问题再补充一点:@Mockbean
和 @Autowired
是对集成测试有意义的注释,因为它们处理 bean 的模拟和注入。单元测试应单独考虑此 class,模拟与其他 class 的交互,因此无需启动应用程序上下文和设置 bean。
我有以下测试:
@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);
}
}
没关系,它 运行s,但我想知道有没有办法 运行 将其作为单元测试而不是集成测试,并且仍然使用 @MockBean @Autowired。还是我漏掉了什么?
我试着只留下@ExtendWith(SpringExtension.class),但我得到一个关于未找到 BookServiceImpl bean 的异常。
我知道如何使用 MockitoExtension 和@Mock、@InjectMocks 来做到这一点,但我想知道是否有更多的 SpringBoot 方法来做到这一点?
删除
@SpringBootTest
,这将加载整个上下文并减慢您的测试速度。@MockBean
的作用是从指定的bean 中创建一个mock 并将其添加到上下文中。由于没有上下文 运行,因此没有必要使用@MockBean
用
@RunWith(SpringRunner.class)
注释你的单元测试class
对于注入依赖项,这是一个很好的做法,可以显式创建配置文件和模拟 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; } }
然后将你的测试class写成:
@ActiveProfiles("test")
@Import(BookServiceTestConfiguration .class)
@RunWith(SpringRunner.class)
public class BookServiceUnitTest {
@Autowired
private BookService bookService;
// write unit tests
}
- 有关更多信息,请阅读 this article
您可以通过四个步骤对其进行单元测试:
- 删除
@SpringBootTest
注释,因为它正在旋转整个 Spring 上下文——对所有协作者都被模拟的单元测试没有用 - 从 BookServiceImpl 声明中删除
@Autowired
注释并添加一个@BeforeEach
设置方法,在其中初始化bookService
传递bookRepository
和libraryService
作为参数 - 在 ExtendWith 注释中使用
MockitoExtension
而不是SpringExtension
。在这里,我假设您能够使用像 Mockito 这样的库来模拟您的合作者 - 使用 Mockito 的
@Mock
而不是@MockBean
,因为我们是手动初始化bookService
所以不需要处理 Spring 个 beans
关于您的第一个问题再补充一点:@Mockbean
和 @Autowired
是对集成测试有意义的注释,因为它们处理 bean 的模拟和注入。单元测试应单独考虑此 class,模拟与其他 class 的交互,因此无需启动应用程序上下文和设置 bean。