Java Mocking入门—使用Mockito

本文介绍如何在Java项目中使用Mockito进行单元测试,特别是在处理依赖其他组件时,通过使用mock对象来隔离测试环境,实现对数据访问层(DAL)类的独立测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java Mocking入门—使用Mockito

我们都会编写单元测试程序,但我们当前所面临的挑战是被测单元可能依赖于其他组件。而对于单元测试配置其他组件,绝对是过枉矫正。相反,我们可以使用Mocks框架代替其他组件,继续进行单元测试。

为了展现如何使用mock框架,我编写一个数据访问层(DAL),该类对应用提供了一套API 接口来访问和修改数据库中的数据。之后在不需要连接数据库的情况下,对DAL类进行单元测试。数据库可以是本地数据库、远程数据库、文件系统或者任何可以储存和检索数据的地方。使用DAL类帮助我们 将数据映射操作从应用代码中分离出来。

使用maven建立一个Java工程。

1
mvn archetype:generate -DgroupId=info.sanaulla -DartifactId=MockitoDemo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode= false

以上操作建立了一个MockitoDemo文件夹,然后创建源文件和测试文件的整个目录结构。

考虑下面这个示例模型类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package info.sanaulla.models;
 
import java.util.List;
 
/**
* Model class for the book details.
*/
public class Book {
 
   private String isbn;
   private String title;
   private List<String> authors;
   private String publication;
   private Integer yearOfPublication;
   private Integer numberOfPages;
   private String image;
 
   public Book(String isbn,
               String title,
               List<String> authors,
               String publication,
               Integer yearOfPublication,
               Integer numberOfPages,
               String image){
 
     this .isbn = isbn;
     this .title = title;
     this .authors = authors;
     this .publication = publication;
     this .yearOfPublication = yearOfPublication;
     this .numberOfPages = numberOfPages;
     this .image = image;
 
   }
 
   public String getIsbn() {
     return isbn;
   }
 
   public String getTitle() {
     return title;
   }
 
   public List<String> getAuthors() {
     return authors;
   }
 
   public String getPublication() {
     return publication;
   }
 
   public Integer getYearOfPublication() {
     return yearOfPublication;
   }
 
   public Integer getNumberOfPages() {
     return numberOfPages;
   }
 
   public String getImage() {
     return image;
   }
}

操作Book模型类的DAL类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package info.sanaulla.dal;
 
import info.sanaulla.models.Book;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
 
/**
* API layer for persisting and retrieving the Book objects.
*/
public class BookDAL {
 
   private static BookDAL bookDAL = new BookDAL();
 
   public List<Book> getAllBooks(){
       return Collections.EMPTY_LIST;
   }
 
   public Book getBook(String isbn){
       return null ;
   }
 
   public String addBook(Book book){
       return book.getIsbn();
   }
 
   public String updateBook(Book book){
       return book.getIsbn();
   }
 
   public static BookDAL getInstance(){
       return bookDAL;
   }
}

当前DAL层以上没有任何功能,我们将对这段代码TDD进行单元测试。DAL层可能与ORM映射API或者数据库API通讯,而我们不关心的这些API是如何设计的。

测试驱动DAL层

对单元测试和Java Mock有很多框架,对这个例子,我将选择JUnit做单元测试,Mockito作为Java mock。我们会在Maven的pom.xml文件中更新依赖属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 <a href=" http://maven.apache.org/maven-v4_0_0.xsd">http://maven.apache.org/maven-v4_0_0.xsd"</ a >>
   < modelVersion >4.0.0</ modelVersion >
   < groupId >info.sanaulla</ groupId >
   < artifactId >MockitoDemo</ artifactId >
   < packaging >jar</ packaging >
   < version >1.0-SNAPSHOT</ version >
   < name >MockitoDemo</ name >
   < url >http://maven.apache.org</ url >
   < dependencies >
     <!-- Dependency for JUnit -->
     < dependency >
       < groupId >junit</ groupId >
       < artifactId >junit</ artifactId >
       < version >4.10</ version >
       < scope >test</ scope >
     </ dependency >
     <!-- Dependency for Mockito -->
     < dependency >
       < groupId >org.mockito</ groupId >
       < artifactId >mockito-all</ artifactId >
       < version >1.9.5</ version >
       < scope >test</ scope >
     </ dependency >
   </ dependencies >
</ project >

现在进行BookDAL类的单元测试。单元测试中,我们将注入mock数据到BookDAL类,因此我们可以不依赖数据源就可以完成API的测试。

最初我们有一个空的测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class BookDALTest {
   public void setUp() throws Exception {
 
   }
 
   public void testGetAllBooks() throws Exception {
 
   }
 
   public void testGetBook() throws Exception {
 
   }
 
   public void testAddBook() throws Exception {
 
   }
 
   public void testUpdateBook() throws Exception {
 
   }
}

我们将使用下面的setUp()函数把BookDAL类注入mock对象,并设置mock对象数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class BookDALTest {
 
   private static BookDAL mockedBookDAL;
   private static Book book1;
   private static Book book2;
 
   @BeforeClass
   public static void setUp(){
     //Create mock object of BookDAL
     mockedBookDAL = mock(BookDAL. class );
 
     //Create few instances of Book class.
     book1 = new Book( "8131721019" , "Compilers Principles" ,
             Arrays.asList( "D. Jeffrey Ulman" , "Ravi Sethi" , "Alfred V. Aho" , "Monica S. Lam" ),
             "Pearson Education Singapore Pte Ltd" , 2008 , 1009 , "BOOK_IMAGE" );
 
     book2 = new Book( "9788183331630" , "Let Us C 13th Edition" ,
             Arrays.asList( "Yashavant Kanetkar" ), "BPB PUBLICATIONS" , 2012 , 675 , "BOOK_IMAGE" );
 
     //Stubbing the methods of mocked BookDAL with mocked data.
     when(mockedBookDAL.getAllBooks()).thenReturn(Arrays.asList(book1, book2));
     when(mockedBookDAL.getBook( "8131721019" )).thenReturn(book1);
     when(mockedBookDAL.addBook(book1)).thenReturn(book1.getIsbn());
     when(mockedBookDAL.updateBook(book1)).thenReturn(book1.getIsbn());
   }
 
   public void testGetAllBooks() throws Exception {}
 
   public void testGetBook() throws Exception {}
 
   public void testAddBook() throws Exception {}
 
   public void testUpdateBook() throws Exception {}
}

在上面的setUp()方法中,我做了:

1. 创建一个BookDAL的mock对象

1
BookDAL mockedBookDAL = mock(BookDAL. class );

2. 存根带mock数据的BookDAL对象的API,这样无论何时调用API都可以返回mock数据。

1
2
3
4
5
//When getAllBooks() is invoked then return the given data and so on for the other methods.
when(mockedBookDAL.getAllBooks()).thenReturn(Arrays.asList(book1, book2));
when(mockedBookDAL.getBook( "8131721019" )).thenReturn(book1);
when(mockedBookDAL.addBook(book1)).thenReturn(book1.getIsbn());
when(mockedBookDAL.updateBook(book1)).thenReturn(book1.getIsbn());

填充剩余的测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package info.sanaulla.dal;
 
import info.sanaulla.models.Book;
import org.junit.BeforeClass;
import org.junit.Test;
 
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
 
import java.util.Arrays;
import java.util.List;
 
public class BookDALTest {
 
   private static BookDAL mockedBookDAL;
   private static Book book1;
   private static Book book2;
 
   @BeforeClass
   public static void setUp(){
     mockedBookDAL = mock(BookDAL. class );
     book1 = new Book( "8131721019" , "Compilers Principles" ,
             Arrays.asList( "D. Jeffrey Ulman" , "Ravi Sethi" , "Alfred V. Aho" , "Monica S. Lam" ),
             "Pearson Education Singapore Pte Ltd" , 2008 , 1009 , "BOOK_IMAGE" );
 
     book2 = new Book( "9788183331630" , "Let Us C 13th Edition" ,
             Arrays.asList( "Yashavant Kanetkar" ), "BPB PUBLICATIONS" , 2012 , 675 , "BOOK_IMAGE" );
 
     when(mockedBookDAL.getAllBooks()).thenReturn(Arrays.asList(book1, book2));
     when(mockedBookDAL.getBook( "8131721019" )).thenReturn(book1);
     when(mockedBookDAL.addBook(book1)).thenReturn(book1.getIsbn());
 
     when(mockedBookDAL.updateBook(book1)).thenReturn(book1.getIsbn());
 
   }
 
   @Test
   public void testGetAllBooks() throws Exception {
 
     List<Book> allBooks = mockedBookDAL.getAllBooks();
     assertEquals( 2 , allBooks.size());
     Book myBook = allBooks.get( 0 );
     assertEquals( "8131721019" , myBook.getIsbn());
     assertEquals( "Compilers Principles" , myBook.getTitle());
     assertEquals( 4 , myBook.getAuthors().size());
     assertEquals((Integer) 2008 , myBook.getYearOfPublication());
     assertEquals((Integer) 1009 , myBook.getNumberOfPages());
     assertEquals( "Pearson Education Singapore Pte Ltd" , myBook.getPublication());
     assertEquals( "BOOK_IMAGE" , myBook.getImage());
   }
 
   @Test
   public void testGetBook(){
 
     String isbn = "8131721019" ;
 
     Book myBook = mockedBookDAL.getBook(isbn);
 
     assertNotNull(myBook);
     assertEquals(isbn, myBook.getIsbn());
     assertEquals( "Compilers Principles" , myBook.getTitle());
     assertEquals( 4 , myBook.getAuthors().size());
     assertEquals( "Pearson Education Singapore Pte Ltd" , myBook.getPublication());
     assertEquals((Integer) 2008 , myBook.getYearOfPublication());
     assertEquals((Integer) 1009 , myBook.getNumberOfPages());
 
   }
 
   @Test
   public void testAddBook(){
     String isbn = mockedBookDAL.addBook(book1);
     assertNotNull(isbn);
     assertEquals(book1.getIsbn(), isbn);
   }
 
   @Test
   public void testUpdateBook(){
 
     String isbn = mockedBookDAL.updateBook(book1);
     assertNotNull(isbn);
     assertEquals(book1.getIsbn(), isbn);
   }
}

使用maven命令: mvn test进行测试。输出如下:

1
2
3
4
5
6
7
8
9
10
11
-------------------------------------------------------
  T E S T S
-------------------------------------------------------
Running info.sanaulla.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.029 sec
Running info.sanaulla.dal.BookDALTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.209 sec
 
Results :
 
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0

至此,通过使用mock框架,在不用实际配置数据源的情况下,就可以测试DAL类。

原文链接:  dzone 翻译:  ImportNew.com liken
译文链接:  http://www.importnew.com/10083.html
转载请保留原文出处、译者和译文链接。]

转载于:https://www.cnblogs.com/developer-ios/p/5382052.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值