目录

  • 测试Service组件和使用模拟组件辅助测试
  • 测试Service组件
  • 1、测试添加书籍的方法
  • 代码示例:
  • 2、测试查询书籍的方法
  • 借助于模拟组件来完成测试--Mockit
  • 使用模拟组件测试Service组件的查询书籍的方法
  • 涉及注解:
  • 主要点:
  • 步骤:
  • 代码
  • 使用模拟组件测试添加书籍的方法


测试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注解 方式

springboot框架中service文件可以调用controller文件_spring boot



代码示例:
//测试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);
    }



2、测试查询书籍的方法

//测试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);
    }



借助于模拟组件来完成测试–Mockit

假设要测试的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;
    }