上一篇我介绍了使用stub进行单元测试。那么mock objects和stub有何区别?什么情况下使用mock objects呢?

下面摘自junit in action书中的解释:

mock objects (或者简称为 mocks),非常适用于将某一部分代码与其他代问隔离开来,并对这部分代码进行测试。

mocks 替换了测试中与你的方法协作的对象,从而提供个隔离层。从这一点来讲,它与 stub 有些类似。不过相似之处也仅限于

此,因为mocks 并不实现任何逻辑 它们只是提供了一种使测试能够控制仿造类的所有业务逻辑方法行为的方法的空壳。

下面以一个账户转账的测试用例加以说明。大家可以比较下其与stub的区别。

创建账户类

package com.lhy.junitkaifa.mocks.account;

/**
* 账户
*
* @author xusucheng
* @create 2018-12-22
**/
public class Account {
private String accountId;
private long balance; public Account(String accountId, long balance){
this.accountId = accountId;
this.balance = balance;
} public void debit(long amount){
this.balance-=amount;
} public void credit(long amount){
this.balance+=amount;
} public long getBalance(){
return this.balance;
}
}

创建配置接口与实现

package com.lhy.junitkaifa.mocks.configurations;

/**
* 配置
*
* @author xusucheng
* @create 2018-12-22
**/
public interface Configuration {
String getSQL(String sqlString);
}
package com.lhy.junitkaifa.mocks.configurations;

/**
* @author xusucheng
* @create 2018-12-22
**/
public class DefaultConfiguration implements Configuration {
public DefaultConfiguration(String configuration){ } @Override
public String getSQL(String sqlString) {
return null;
}
}

创建账户管理接口与实现

package com.lhy.junitkaifa.mocks.account;

/**
* 账户管理接口
*
* @author xusucheng
* @create 2018-12-22
**/
public interface AccountManager {
Account findAccountById(String userId); void updateAccount(Account account);
}
package com.lhy.junitkaifa.mocks.account;

import com.lhy.junitkaifa.mocks.configurations.Configuration;
import com.lhy.junitkaifa.mocks.configurations.DefaultConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; /**
* 账户管理接口实现
*
* @author xusucheng
* @create 2018-12-22
**/
public class AccountManagerImpl implements AccountManager {
private Log logger; private Configuration configuration; public AccountManagerImpl(){
this(LogFactory.getLog(AccountManagerImpl.class),new DefaultConfiguration("technical"));
} public AccountManagerImpl(Log logger, Configuration configuration){
this.logger = logger;
this.configuration = configuration;
} @Override
public Account findAccountById(String userId) {
this.logger.debug("Getting account for user["+userId+"]");
this.configuration.getSQL("FIND_ACCOUNT_BY_ID"); return null;
} @Override
public void updateAccount(Account account) {
//Do nothing.
} }

创建账户管理服务类

package com.lhy.junitkaifa.mocks.account;

/**
* 账户管理服务
*
* @author xusucheng
* @create 2018-12-22
**/
public class AccountService {
private AccountManager accountManager; /**
* 注入具体实现
* @param accountManager
*/
public void setAccountManager(AccountManager accountManager){
this.accountManager = accountManager;
} public void transfer(String fromId, String toId, long amount){
//转出账户
Account from = this.accountManager.findAccountById(fromId);
//转入账户
Account to = this.accountManager.findAccountById(toId);
from.debit(amount);
to.credit(amount);
this.accountManager.updateAccount(from);
this.accountManager.updateAccount(to);
}
}

创建测试用账户管理接口

package com.lhy.junitkaifa.mocks.account;

import java.util.HashMap;
import java.util.Map; /**
* @author xusucheng
* @create 2018-12-22
**/
public class MockAccountManager implements AccountManager{
//保存所有账户
private Map<String,Account> accounts = new HashMap<>(); /**
* 添加账户
* @param userId
* @param account
*/
public void addAccount(String userId, Account account){
this.accounts.put(userId,account);
} /**
* 获取账户
* @param userId
* @return
*/
@Override
public Account findAccountById(String userId) {
return this.accounts.get(userId);
} @Override
public void updateAccount(Account account) {
//不干事
}
}

创建测试用日志类

package com.lhy.junitkaifa.mocks.account;

import org.apache.commons.logging.Log;

/**
* @author xusucheng
* @create 2018-12-22
**/
public class MockLog implements Log {
@Override
public boolean isFatalEnabled() {
return false;
} @Override
public boolean isErrorEnabled() {
return false;
} @Override
public boolean isWarnEnabled() {
return false;
} @Override
public boolean isInfoEnabled() {
return false;
} @Override
public boolean isDebugEnabled() {
return false;
} @Override
public boolean isTraceEnabled() {
return false;
} @Override
public void fatal(Object o) { } @Override
public void fatal(Object o, Throwable throwable) { } @Override
public void error(Object o) { } @Override
public void error(Object o, Throwable throwable) { } @Override
public void warn(Object o) { } @Override
public void warn(Object o, Throwable throwable) { } @Override
public void info(Object o) { } @Override
public void info(Object o, Throwable throwable) { } @Override
public void debug(Object o) { } @Override
public void debug(Object o, Throwable throwable) { } @Override
public void trace(Object o) { } @Override
public void trace(Object o, Throwable throwable) { }
}

创建测试用配置类

package com.lhy.junitkaifa.mocks.configurations;

/**
* @author xusucheng
* @create 2018-12-22
**/
public class MockConfiguration implements Configuration {
public void setSQL(String sqlString){ } @Override
public String getSQL(String sqlString) {
return null;
}
}

创建测试类

package com.lhy.junitkaifa.mocks.account;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
* @author xusucheng
* @create 2018-12-22
**/
public class TestAccountService {
@Test
public void testTransferOk(){
MockAccountManager mockAccountManager = new MockAccountManager();
Account from = new Account("1",200);
Account to = new Account("2",100);
mockAccountManager.addAccount("1", from);
mockAccountManager.addAccount("2", to); AccountService accountService = new AccountService();
accountService.setAccountManager(mockAccountManager);
accountService.transfer("1","2",50); assertEquals(150,from.getBalance());
assertEquals(150,to.getBalance());
}
}

运行测试

junit使用mock objects进行单元测试的更多相关文章

  1. 换种思路写Mock,让单元测试更简单

    开篇引入 单元测试中的Mock方法,通常是为了绕开那些依赖外部资源或无关功能的方法调用,使得测试重点能够集中在需要验证和保障的代码逻辑上.在定义Mock方法时,开发者真正关心的只有一件事:" ...

  2. What is the purpose of mock objects?

    Since you say you are new to unit testing and asked for mock objects in "layman's terms", ...

  3. 学习笔记:首次进行JUnit+Ant构建自动的单元测试(二)

    关键字:JUnit,Ant,单元测试 终于把JUnit+Ant构建单元测试的大概了解了,其实我实践的过程是对了,只是指导博客(看到这里不懂请看我上一篇博客)本身的错误“成功”把我带入“坑”,有时候网友 ...

  4. 学习笔记:首次进行JUnit+Ant构建自动的单元测试(一)

    指导博客:https://blog.csdn.net/Cceking/article/details/51692010 基于软件测试的需求,使用JUnit+Ant构建自动的单元测试. IDE:ecli ...

  5. 有效使用Mock编写java单元测试

    Java单元测试对于开发人员质量保证至关重要,尤其当面对一团乱码的遗留代码时,没有高覆盖率的单元测试做保障,没人敢轻易对代码进行重构.然而单元测试的编写也不是一件容易的事情,除非使用TDD方式,否则编 ...

  6. 使用junit进行最简单的单元测试

    使用junit进行最简单的单元测试 使用工具: jdk IDEA Maven 第一步 创建一个Maven项目 第二步 导入junit依赖 <dependency> <groupId& ...

  7. 【java测试】Junit、Mock+代码覆盖率

    原文见此处 单元测试是编写测试代码,用来检测特定的.明确的.细颗粒的功能.单元测试并不一定保证程序功能是正确的,更不保证整体业务是准备的. 单元测试不仅仅用来保证当前代码的正确性,更重要的是用来保证代 ...

  8. 使用 Python Mock 类进行单元测试

    数据类型.模型或节点——这些都只是mock对象可承担的角色.但mock在单元测试中扮演一个什么角色呢? 有时,你需要为单元测试的初始设置准备一些“其他”的代码资源.但这些资源兴许会不可用,不稳定,或者 ...

  9. 使用Python中的mock模块进行单元测试

    在进行单元测试的时候,有时候会遇到这种情况: 出于某些原因,我们不想测试某一部分内容,但是我们想要测试的部分却依赖这部分内容. 这时候,可以使用mock模块来模拟调用这部分内容,并给出返回结果,举例如 ...

  10. JUNIT -- springMVC的action进行单元测试

    原文:http://blog.csdn.net/gaopeng0071/article/details/49946575 我开发环境springMVC版本3.0.4 样例代码: package com ...

随机推荐

  1. [转帖]TLS/SSL (Schannel SSP) 中的密码套件

    https://learn.microsoft.com/zh-cn/windows/win32/secauthn/cipher-suites-in-schannel 密码套件是一组加密算法. TLS/ ...

  2. [转帖]Zookeeper集群搭建(3个节点为例)

    Zookeeper集群搭建 1.说明 本文用的linux版本:centos6,准备3台centos6虚拟机,给他们安装zookeeper,每一台的安装过程相同,你也可以安装一台,然后克隆出另外两台.主 ...

  3. [转帖]使用 goofys 挂载 S3 bucket 为文件系统

    https://xie.infoq.cn/article/7f178e0a1315f758d77c6c2bb 背景 公司的 gitlab 目前都是直接存储在物理盘上,为了确保数据不会丢失,需要重复多次 ...

  4. [转帖]Day63_Kafka(一)

    第一讲 Kafka基础操作 课程大纲 课程内容 学习效果 掌握目标 Kafka简介 消息队列 掌握 Kafka简介 Kafka分布式环境 Kafka操作 Kafka shell 掌握 Kafka ap ...

  5. [转帖]Linux shell 单引号和双引号

    https://www.cnblogs.com/airoot/p/15324883.html 在编写shell脚本的时候经常会用到引号,有些时候却老是忘记单引号和双引号之间的区别,所以就整理一下供以后 ...

  6. [转帖]Linux系统硬链接和软链接具体实例讲解(超详细)

    简介 在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名.文件名仅是为了方便人们的记忆和使用, ...

  7. [转帖]20191022-从Jenkins NativeOOM到Java8内存

    我把老掉牙的Jenkins升级了,它跑了几天好好的:后来我有一个python脚本使用JenkinsAPI 0.3.9每隔2.5分钟发送约300余get请求,结果过了3天,它就挂了:当我开两个脚本时,4 ...

  8. 【行云流水线】满足你对工作流编排的一切幻想~skr

    流水线模型 众所周知,DevOps流水线(DevOps pipeline)的本质是实现自动化工作流程,用于支持软件开发.测试和部署的连续集成.交付和部署(CI/CD)实践.它是DevOps方法论的核心 ...

  9. vim 从嫌弃到依赖(4)—— .命令

    通过之前几篇文章的介绍,如果各位小伙伴能够勤加练习,并在日常工作上经常使用,那么相信那些内容已经会对工作效率的提升产生好的影响.但是如果那些就是vim的全部的话,我们也就没那么大的必要花这么大的精力来 ...

  10. Jmeter报错权限不够

    Jmeter报错权限不够 解决办法: chmod +x jmeter