# Junit+Jmokit单元测试
标签(空格分隔):java单元测试
---
> 原理:mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
- 实质是一种替身的概念,代码基本上完全面向对象 JMockit的API易用,丰富! 写出来的Mock程序代码完全面向对象
#第一阶段 环境准备
1.开发环境已正确配置
idea工具 maven jdk
2.工程解决JUnit依赖关系(pom.xml)
junit依赖包
jmockit依赖包
Junit Generator架包 用于代码生成器的类
pom.xml 依赖版本
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.15</version>
</dependency>
1.打开Settings窗口搜索Junit Generator,如图(两个插件都勾选添加):
![搜索juni插件.jpg-66.5kB][1]
2.JUnitGenerator V2.0插件,可以帮助我们自动生成测试代码。如果搜索junit没有JUnitGenerator V2.0时,如下图操作(下载添加):
![下载插件或者导入插件.jpg-137.7kB][2]
3.JUnitGenerator V2.0插件 配置
![日期乱码.jpg-142kB][3]
4.JUnitGenerator V2.0代码生成操作如下:
生成路径是当前类路径前面加一个test (test.com.bestpay.algorithm.impl)
![生成测试类的.png-88.2kB][4]
#第二阶段 逻辑
###JMockit有两种测试方式,一种是基于行为的,一种是基于状态的测试。
Behavior-oriented(Expectations & Verifications :
通俗点讲,Behavior-oriented是基于行为的mock,对mock目标代码的行为进行模仿,更像黑盒测试
State-oriented(MockUp<GenericType>) :
是基于状态的mock,是站在目标测试代码内部的。可以对传入的参数进行检查、匹配,才返回某些结果,类似白盒
而State-oriented的 new MockUp基本上可以mock任何代码或逻辑,MockUp用于静态方法打桩比较多。
jmockit基本有三个步骤:
(1)打桩。指定要打桩类和函数,模拟返回结果。Expectations()
(2)调用被测方法。被测逻辑执行过程中,之前的打桩数据生效。
(3)判断测试结果是否符合预期。Verifications()
#第三阶段 实操
1.@RunWith(JMockit.class)都被用作运行测试套件 增加运行注解,在这个才可以mocked,一般用于类之上
#####在声明模拟字段和参数时,我们可以使用三种不同的模拟注释
- @Mocked:Mocked修饰的类/接口,是让Jmockit生成一个Mocked对象,这个对象的方法(包含静态方法)返回默认值,如果返回类型是其他引用类型,则返回这个引用类型的Mocked对象.
- @Tested:表示修饰的类,表示测试对象.
- @Injectable:也表示Mocked一个对象,相比Mocked,只不过影响类的一个类的实例.
- Expectations :主要用于录制类/对象的调用,返回值是什么.
- @Mock直接Mock对象方法
- 用Expectation来Mock类于Expectation来Mock实例唯一的不同在于,前者影响类的所有实例,后者只影响某一个类的实例
CountDemo.class
public class Count extends BaseRedisAggregation {
public Count() {
name = "Count";
}
@Override
public Object process(SourceData data) {
Map fields = paramsParser(data);
Jedis redis = redisSource.getRedis();
final String key = fields.get("key").toString();
final Integer target = 1;
final String maxStr = redis.hget(key, name);
if (StringUtils.isNotBlank(maxStr)) {
redis.hincrBy(key, name, 1);
if (redisSource.expireTime != -1) {
redis.expire(key, aggRange * redisSource.expireTime);
}
}
computeAggregation(fields.get("dimsKey").toString(), fields.get("timeKey").toString(),
fields.get("singleKey").toString(), aggRange, aggDimention, redis);
redis.close();
return null;
}
@Override
public Map<String, Object> paramsParser(SourceData data) {
String dimsKey = keyPreffix + data.get("dKey");
String tKey = data.get("tKey");
String timeKey = "";
if (StringUtils.isNotBlank(tKey)) {
timeKey = TimeTransformater.getTimeStr(tKey, aggDimention);
}
String singleKey = "Single" + dimsKey;
String key = singleKey + timeKey;
String finalTimeKey = timeKey;
Map<String, Object> algorithmnFileds = new HashMap<String, Object>() {{
put("dimsKey", dimsKey);
put("timeKey", finalTimeKey);
put("key", singleKey + finalTimeKey);
put("target", data.get("target"));
put("singleKey", singleKey);
}};
return algorithmnFileds;
}
public void computeAggregation(String dimKey, String timeStr, String singleKey, int range, char dimensionType, Jedis redis) {
{
int totalCount = 0;
for (int i = 0; i < range; i++) {
String timeKey = "";
if (dimensionType != '0') {
timeKey = TimeTransformater.getLastIntervalTimeStr(dimensionType, timeStr, i);
}
String currRes = redis.hget(singleKey + timeKey,name);
if (StringUtils.isNoneBlank(currRes)) {
totalCount += Integer.valueOf(currRes);
}
}
redis.hset(dimKey, name, String.valueOf(totalCount));
redis.expire(dimKey, 24 * 60 * 60);
}
}
}
####测试类 CountTestDemo.class
/**
* Count Tester.
* @author <Authors name>
* @since <pre>01/30, 2019</pre>
* @version 1.0
*/
@RunWith(JMockit.class)
public class CountTest {
@Tested
Count count;
@Mocked
SourceData sourceDatas;
@Mocked
TimeTransformater timeTransformaters;
@Mocked
Jedis jedis;
@Before
public void before() throws Exception {}
@After
public void after() throws Exception {}
/**
* Method: process(SourceData data)
*/
@Test
public void testComputeAggregation() throws Exception {
//打桩
new Expectations(){
{
timeTransformaters.getLastIntervalTimeStr(anyChar,anyString,anyInt); result = 1L;
}
{
jedis.hget(anyString, anyString); result = "100";
}
{
jedis.hset(anyString, anyString, anyString);result = 1l;
}
{
jedis.expire(anyString, anyInt); result =100l;
}
};
count.computeAggregation("1","1","1",1,'a',jedis);
//判断测试结果
new Verifications() {
{
jedis.hset("1","Count","100");times=1;
}
};
}
}
> ####常见坑:
> 1.@Tested /@Mocked 时保持格式一致统一对齐
> 2.junit/jmockit依赖架包尽量不要存在多个版本
> 3.测试中方法中,有用到继承属性值,在打桩后直接调用当前类的属性赋予值
1.@Tested /@Mocked 时保持格式一致统一对齐
![格式2.png-48.9kB][5]
3.测试中方法中,有用到继承属性值,在打桩后直接调用当前类的属性赋予值。
![例子.png-46.9kB][6]
[1]: http://static.zybuluo.com/ziyi/afgogf3c5cu9sd99ft9x0kv4/%E6%90%9C%E7%B4%A2juni%E6%8F%92%E4%BB%B6.jpg
[2]: http://static.zybuluo.com/ziyi/ag7rxeh0ycgacgh91t297hmj/%E4%B8%8B%E8%BD%BD%E6%8F%92%E4%BB%B6%E6%88%96%E8%80%85%E5%AF%BC%E5%85%A5%E6%8F%92%E4%BB%B6.jpg
[3]: http://static.zybuluo.com/ziyi/bkzylyo385je9utf9xcsata4/%E6%97%A5%E6%9C%9F%E4%B9%B1%E7%A0%81.jpg
[4]: http://static.zybuluo.com/ziyi/drtqcs12qmb35jbs4v70g8lb/%E7%94%9F%E6%88%90%E6%B5%8B%E8%AF%95%E7%B1%BB%E7%9A%84.png
[5]: http://static.zybuluo.com/ziyi/jsc88jokl9dqvqc5glbg90dd/%E6%A0%BC%E5%BC%8F2.png
[6]: http://static.zybuluo.com/ziyi/5n5vjbscn063g43gk04p56r4/%E4%BE%8B%E5%AD%90.png
网友评论