情景描述如下:
假设我们有一个BookService类,该类简单实现了借书和还书两个功能,但是BookService需要调用BookManager接口与数据库交互。
现在我们有一个尚未实现的接口BookManager(该借口主要用于数据库操作),假设现在我们没有数据库环境,那么我们就可以通过EasyMock框架来模拟实现其功能。
该情景下,使用EasyMock框架进行单元测试基本步骤如下:
1.调用cearteMock方法,来创建一个mock(模拟对象)来模拟BookManager接口
2.设定Mock对象的预期行为和输出
3.将Mock对象切换到Replay状态
4.调用Mock对象进行单元测试
5.对Mock对象的行为进行验证
注意事项:
1.先了解Mock Object的相关知识,再来使用EasyMock框架加深理解。
2.需要到EasyMock官网(http://easymock.org/)下载easymock的压缩包,然后把其中的easymock.jar包导入项目中。
(选中项目,右键选中构建路径,选择添加外部jar包,去找到对应的easymock.jar包位置即可)
具体代码示例如下:
//Book实体类
public class Book {
private String name;// 书名
private String isbn;//
private double price;// 价格
private boolean inShell; // 是否在架上
public Book() {
}
public Book(String name, String isbn, double price, boolean inShell) {
this.name = name;
this.isbn = isbn;
this.price = price;
this.inShell = inShell;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getISBN() {
return this.isbn;
}
public void setISBN(String isbn) {
this.isbn = isbn;
}
public double getPrice() {
return this.price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isInShell() {
return this.inShell;
}
public void setInShell(boolean inShell) {
this.inShell = inShell;
}
}
//BookManager接口,用于和数据库交互
public interface BookManager {
Book findBook(String isbn); // 根据isbn在数据库中找到相应的书籍
void updateBook(Book book); // 更新数据库中书籍的状态(是否在书架上)
}
//BookService类,简单实现借书,还书两个功能
public class BookService {
private BookManager bookManager;
public BookService(BookManager bookManager) {
this.bookManager = bookManager;
}
/**
* 借书
*
* @param isbn
* @return
*/
public boolean borrowBook(String isbn) {
Book book = bookManager.findBook(isbn);
if (book != null && book.isInShell()) {
// 书籍存在并且在书架上
book.setInShell(false);
bookManager.updateBook(book);
return true;
}
return false;
}
/**
* 还书
*
* @param isbn
* @return
*/
public boolean returnBook(String isbn) {
Book book = bookManager.findBook(isbn);
if (book != null && !book.isInShell()) {
// 书籍存在且不在书架上
book.setInShell(true);
return true;
}
return false;
}
}
//使用EasyMock框架进行模拟测试
import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestBookServiceEasyMock {
// 声明我们想要mock的对象
// 核心EasyMock框架只能mock接口对象
private BookManager mockBookManager = null;
private Book book1 = null;
private Book book2 = null;
@Before
public void setUp() throws Exception {
// 调用 createMock方法,来创建一个mock来模拟BookManager
mockBookManager = createMock("mockBookManager", BookManager.class);
// 创建两本书
book1 = new Book("软件测试自动化", "1", 32.3, true);
book2 = new Book("软件测试过程管理", "2", 35.3, false);
}
@After
public void tearDown() throws Exception {
// 验证Mock对象行为
verify(mockBookManager);
}
// 正常借书
@Test
public void testBorrowBook1() {
// 使用EasyMock我们有两种声明预期的方法
// 当方法的返回值类型为void,我们就在mock object上调用此方法
// 当方法返回任何类型的对象,我们需要使用EasyMock API中的expect和andReturn方法
expect(mockBookManager.findBook("1")).andReturn(book1);
mockBookManager.updateBook(book1);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.borrowBook("1");
assertTrue(flag);
assertFalse(book1.isInShell());
}
// 所借书籍不存在
@Test
public void testBorrowBook2() {
expect(mockBookManager.findBook("3")).andReturn(null);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.borrowBook("3");
assertFalse(flag);
}
// 所借书籍不在书架上
@Test
public void testBorrowBook3() {
expect(mockBookManager.findBook("2")).andReturn(book2);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.borrowBook("2");
assertFalse(flag);
assertFalse(book2.isInShell());
}
// 正常还书
@Test
public void testReturnBook1() {
expect(mockBookManager.findBook("2")).andReturn(book2);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.returnBook("2");
assertTrue(flag);
assertTrue(book2.isInShell());
}
// 所还书籍不存在
@Test
public void testReturnBook2() {
expect(mockBookManager.findBook("3")).andReturn(null);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.returnBook("3");
assertFalse(flag);
}
// 所还书籍已在书架上
@Test
public void testReturnBook3() {
expect(mockBookManager.findBook("1")).andReturn(book1);
// 需要调用 replay方法来切换Mock对象的状态
replay(mockBookManager);
BookService bookService = new BookService(mockBookManager);
boolean flag = bookService.returnBook("1");
assertFalse(flag);
assertTrue(book1.isInShell());
}
}