测试Service组件和使用模拟组件辅助测试
测试Service组件
测试Service组件无需启动Web服务器,所以使用@SpringBootTest(webEnvironment = WebEnvironment.NONE)修饰测试用例类即可
(用NONE表示不启动Web服务器)。
Service组件其实就是一个普通的组件,它不需要借助于Web服务器,也不需要启动模拟Web环境
测试用例类定义接受依赖注入的Service类型的实例变量,然后通过该变量测试Service组件的方法
【Spring Boot提供支持就是】:将被测试的组件(Service)注入到测试用例中
在Spring Boot应用中,测试所有的普通组件都可以使用该方式
1、测试添加书籍的方法
两种方式:
方式一:通过 @ParameterizedTest + @MethodSource 注解的方式来测试
方式二:通过 @ParameterizedTest + @CsvSource注解 方式
代码示例:
//测试Service添加书籍的方法---用参数测试的注解
//通过 @ParameterizedTest + @MethodSource 注解的方式来测试
@ParameterizedTest
//这个注解是通过一个 getBooks 的方法的返回值来为这个测试方法传入参数,getBooks这个方法必须是静态Static修饰的,而且返回的值必须是Stream类型
@MethodSource(value = "getBooks")
public void testAddBook(Book book){
bookService.addBook(book);
}
//因为要测试的方法需要的参数是一个Book对象,可以使用@MethodSource(value = "getBooks")注解来尝试
//getBooks这个方法必须是静态Static修饰的,而且返回的值必须是Stream类型
public static Stream<Book> getBooks(){
//通过Stream流来创建数据
Stream<Book> bookStream = Stream.of(new Book("aaa", new BigDecimal(100), "ljh1"),
new Book("bbb", new BigDecimal(110), "ljh2"),
new Book("ccc", new BigDecimal(120), "ljh3"));
return bookStream;
}
//用旧的 @ParameterizedTest + @CsvSource注解 方式
@ParameterizedTest //允许测试方法接收参数进行测试,和注解 @CsvSource 一起使用,@CsvSource注解用来写参数数据
//参数是一个数组,数组里面的每一个元素就是方法的参数
@CsvSource({"书籍A1,100,ljh", "书籍B2,110,ljh", "书籍C3,120,ljh"})
public void testAddBook02(String name,BigDecimal price,String author){
Book book = new Book(name, price, author);
bookService.addBook(book);
}
测试查询书籍的方法
这个就很普通了
//测试Service查询书籍的方法
@Test
public void testGetAllBooks(){
List<Book> allBooks = bookService.getAllBooks();
allBooks.forEach(book -> System.err.println(book));
}
测试删除书籍的方法,因为需要用到参数id,所以需要使用到这两个注解
@ParameterizedTest //表示这个测试方法是参数测试
@ValueSource(ints = {94,95,96}) //这个注解通过int类型的数组中的元素来作为参数
//测试Service删除书籍的方法
@ParameterizedTest
@ValueSource(ints = {94,95,96})
public void testDeleteBookById(Integer id){
bookService.deleteBookById(id);
}
借助于模拟组件来完成测试
假设要测试的A组件依赖于B组件,但B组件可能根本就没有开发完成,或B组件开发出来了,但没有经过严格的测试。
如果直接对A组件进行测试,此时可能测试出现的错误并不是A组件导致的,而是A组件所依赖的B组件所导致的。
为了避免B组件将错误传给A组件,或者在没有B组件的前提下,能对A组件进行测试
此时就需要提供一个B组件的模拟对象——借助于Mockit即可。
简单来说,service 层依赖 Dao层,我们在测试的时候,如果Dao还没开发,就测试不了,或者说测试的时候出Bug,但是不知道是service层出错还是Dao层出错。
这个时候就需要借助模拟对象 Mockit 来测试了。弄一个假的Dao组件。
使用模拟组件测试Service组件的查询书籍的方法
涉及注解:
@MockBean :声明被修饰的组件将作为模拟组件,而不去使用真实组件,就是这个 bookDao 是模拟出来的,不是正式的 dao 层。
主要点:
BDDMockito.given(this.bookDao.findAll()).willReturn(list);
BDDMockito 定义模拟组件(bookDao)的指定方法(findAll())的返回值(list)
.given() 调用BDDMockito的given()类方法为模拟组件的指定方法直接设置返回值
this.bookDao 就是上面声明的用@MockBean假装注入的bookDao假组件
findAll() 就是我们待会访问的添加书籍的方法
willReturn(list) 就是我们给这个findAll()方法的返回值。
(1)定义一个@MockBean修饰的模拟组件
——该模拟组件就代表了被依赖组件(该组件可能未开发完成,或未经过严格测试)
(2)在测试方法中,调用BDDMockito的given()类方法为模拟组件的指定方法直接设置返回值。
——这样即可基于对模拟组件所设置的返回值来进行测试。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class BookServiceMockBeanTest {
@Autowired
private BookService bookService;
@MockBean //声明被修饰的组件将作为模拟组件,不使用真实组件,就是这个 bookDao 是模拟出来的,不是正式的 dao 层。
private BookDao bookDao;
//测试Service查询书籍的方法
@Test
public void testGetAllBooks() {
//假数据
List<Book> list = new ArrayList<>();
list.add(new Book("zzz", new BigDecimal(100), "ljh1"));
list.add(new Book("xxx", new BigDecimal(110), "ljh2"));
list.add(new Book("vvv", new BigDecimal(120), "ljh3"));
//BDDMockito 定义模拟组件(bookDao)的指定方法(findAll())的返回值(list)
//this.bookDao 就是上面声明的用@MockBean假装注入的bookDao假组件
//.findAll() 就是我们待会访问的添加书籍的方法
//.willReturn(list) 就是我们给这个findAll()方法的返回值。
BDDMockito.given(this.bookDao.findAll()).willReturn(list);
//这个getAllBooks()方法就变成了依赖模拟组件来实现,而不会去调用真实的业务方法。getAllBooks()返回的数据从原本的真实的数据变成了上面模拟组件提供的数据willReturn(list)
List<Book> allBooks = bookService.getAllBooks();
//断言测试,看返回成功的值是不是假数据。
//此处的断言与真实的Dao组件是无关的,它只依赖与模拟的Dao组件。
Assertions.assertEquals("zzz",allBooks.get(0).getName());
Assertions.assertEquals("xxx",allBooks.get(1).getName());
Assertions.assertEquals("vvv",allBooks.get(2).getName());
}
}
使用模拟组件测试添加书籍的方法
//使用模拟组件测试添加书籍的方法
@ParameterizedTest
@MethodSource(value = "getBooks")
public void testAddBook(Book book) {
Book b = new Book(12345, "ggg", new BigDecimal(111), "lll");
//BDDMockito指定this.bookDao模拟组件的save()方法返回的数据是b
BDDMockito.given(this.bookDao.save(book)).willReturn(b);
Integer id = bookService.addBook(book);
//断言
Assertions.assertEquals(12345,id);
}
public static Stream<Book> getBooks() {
//通过Stream流来创建数据
Stream<Book> bookStream = Stream.of(
new Book("aaa", new BigDecimal(100), "ljh1"),
new Book("bbb", new BigDecimal(110), "ljh2"),
new Book("ccc", new BigDecimal(120), "ljh3")
);
return bookStream;
}
删除书籍的方法没法测试,就没有测试了