关于单元测试的一些问题

当我们Javaweb项目中编写单元测试的时候,通常会面临一个普遍的问题:需要测试的类会有很多依赖,而这些依赖的类或者对象又会有很多别的依赖,导致我们在写单元测试的时候几乎需要把完整的业务体系代码编写出来,而在单元测试中将这这些个依赖完整的构建出来是一件很困难的事情,通常这个时候,我们会想到把里面一些需要的依赖“Mock”出来。

Mock及使用Mockito

Mock,从单词层面来讲师仿制和模拟,在软件开发和测试中通常是指模拟对象。

简单地说就是对测试的类所依赖的其他类和对象,进行mock - 构建它们的一个假的对象,定义这些假对象上的行为,然后提供给被测试对象使用。被测试对象像使用真的对象一样使用它们。用这种方式,我们可以把测试的目标限定于被测试对象本身,就如同在被测试对象周围做了一个划断,形成了一个尽量小的被测试目标。

通过这样,我们可以在不编写大量依赖对象的前提下使用少量的代码即可完成整个业务流程的单元测试。具体的使用可以参考下面一个业务中的简单例子。

Mock的框架有很多,最为知名的一个是Mockito,这是一个开源项目,使用广泛。官网:http://site.mockito.org/。

使用实例

  • 创建项目时引入单元测试包和mockito的包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
<scope>test</scope>
</dependency>
  • 新建一个账户对象类 Account
public class Account {
/*
* 账户ID
*/
private String accountId;
/**
* 收支
*/
private long balance; /**
* 初始化账户ID和收支
* @param accountId
* @param initialBalance
*/
public Account(String accountId, long initialBalance){
this.accountId = accountId;
this.balance = initialBalance;
} public void debit(long amount){
this.balance -= amount;
} public void credit(long amount){
this.balance += amount;
} public long getBalance(){
return this.balance;
} }
  • 创建一个账号管理接口,里面包含了一个查找账户对象的方法和一个更新账户信息的方法
public interface AccountManager {

	/**
* 根据userId找到对应账号对象
* @param userId
* @return
*/
Account findAccountForUser(String userId); /**
* 更新账户信息
* @param account
*/
void updateAccount(Account account); }
  • 创建账号管理接口的实现类MockAccountManager,并在其中新增一个账号管理的方法
public class MockAccountManager implements AccountManager {
private Hashtable accounts = new Hashtable(); /**
* 新增一个添加账户的方法
* @param userId
* @param account
*/
public void addAccount(String userId, Account account) {
this.accounts.put(userId, account);
} public Account findAccountForUser(String userId) {
return (Account) this.accounts.get(userId);
} public void updateAccount(Account account) {
// do nothing
} }
  • 创建一个服务类AccountService,通过该类来调用接口中的方法
public class AccountService {
private AccountManager accountManager;
// private MockAccountManager mockAccountManager; public void setAccountManager(MockAccountManager manager) {
accountManager = manager;
} /**
*
* @param senderId 转账人的ID
* @param beneficiaryId 收款人ID
* @param amount 转账金额
*/
public void transfer(String senderId, String beneficiaryId, long amount) {
Account sender = accountManager.findAccountForUser(senderId);
Account beneficiary = accountManager.findAccountForUser(beneficiaryId); //转账账户减少
sender.debit(amount);
//收款账户增加
beneficiary.credit(amount);
//更新转账账户信息
this.accountManager.updateAccount(sender);
//更新收款账户信息
this.accountManager.updateAccount(beneficiary);
} }
  • 创建一个普通的单元测试类来测试这个业务流程
import org.junit.Test;
import junit.framework.TestCase; public class TestAccountService extends TestCase{ @Test
public void testTransferOk(){
//使用MockAccountManager
MockAccountManager mockAccountManager = new MockAccountManager(); //初始化两个账户
Account senderAccount = new Account("1", 200);
Account beneficiaryAccount = new Account("2", 100);
mockAccountManager.addAccount("1", senderAccount);
mockAccountManager.addAccount("2", beneficiaryAccount); //初始化AccountService,将MockManager对象传入
AccountService accountService = new AccountService();
accountService.setAccountManager(mockAccountManager); //转帐操作
accountService.transfer("1", "2", 50); //验证
assertEquals(150, senderAccount.getBalance());
assertEquals(150, beneficiaryAccount.getBalance());
} }
  • 创建一个用Mockito进行测试的类
public class TestMockAccountService extends TestCase {

	@Test
public void testTransferOk() {
Account senderAccount = new Account("1", 200);
Account beneficiaryAccount = new Account("2", 100); // 使用mockito创建一个模拟对象
MockAccountManager mockAccountManager = Mockito.mock(MockAccountManager.class); //mockito自带的控制流写法
when(mockAccountManager.findAccountForUser("1")).thenReturn(senderAccount);
when(mockAccountManager.findAccountForUser("2")).thenReturn(beneficiaryAccount); AccountService accountService = new AccountService();
accountService.setAccountManager(mockAccountManager); // 转帐操作
accountService.transfer("1", "2", 50); // 验证
assertEquals(150, senderAccount.getBalance());
assertEquals(150, beneficiaryAccount.getBalance());
} }

以上。

ps.突然发现直接直接从我有道云笔记拷贝不用修改代码格式,页面效果看起来也还挺棒...

最新文章

  1. Oracle脚本笔记
  2. 关于Docker 常用命令
  3. NodeJS 学习资料
  4. 搭建 Win CE6.0 设备开发环境
  5. mpi中利用自定义归约操作实现merge
  6. 关于通过addClass与removeClass用jquery控制有良好兼容的CSS3样式
  7. 飞雪桌面日历软件 V8.6 免费绿色版
  8. xmanager无法弹出图形化界面。
  9. MPAndroidChart——饼图
  10. 阿里云小程序云应用环境DIY,延长3倍免费期
  11. java 大数运算[转]
  12. SVN:多版本库环境的搭建
  13. springMVC(二): @RequestBody @ResponseBody 注解实现分析
  14. Linux下内存映射文件的用法简介
  15. 怎么调用html5的摄像头,录音,视频?
  16. C++课堂作业(1)
  17. 阿里云经典网络和专有 专有自己设置网络和私网IP
  18. 编写高质量代码改善C#程序的157个建议——建议31:在LINQ查询中避免不必要的迭代
  19. 推荐下载CentOS下各种组件的网址
  20. Java中将时间戳转化为Date类型

热门文章

  1. java傻瓜简单100%一定看的懂新手安装教程
  2. python 序列:字符串、列表、元组
  3. Windows Azure系列-- 配置Azure Power Shell
  4. android项目 之 记事本(11) ----- 加入数据库
  5. 具体解释Java虚拟机类载入
  6. 十一、Spring Boot 集成Shiro和CAS
  7. attr设置checked,disabled等属性失效的问题,jquery的attr和prop的区别
  8. 「mysql优化专题」详解引擎(InnoDB,MyISAM)的内存优化攻略?(9)
  9. ios应用版本号设置规则
  10. 《写给大家看的设计书(第3版)》【PDF】下载