软件测试之单元测试
作者:网络转载 发布时间:[ 2016/5/16 11:16:00 ] 推荐标签:软件测试 单元测试
幸好 findService 方法还有一个返回值,可以让我们可以像 StringUtil.isEmpty 一样验证返回结果。为了测试正确的结果,我们还需要在数据库中提前插入一对method-service信息,并保证 ClientFactory 可以找到这个服务。同时还需要在 ClientFactory 和 AppInfoDAO 的实现代码里面打一些log,这样可以观察到查询服务和读数据库时候的一些信息,以保证这个测试的正常运行。测试错误情况比较简单,只需要随便给 findService 方法输入一个字符串参数,观察返回结果或者异常情况即可。这种测试是典型的功能测试,事实上,整个过程是在模拟一个正常的业务流程,但是这种测试时非常脆弱和不稳定的,ClientFactory 和 AppInfoDAO 内部发生的变化是不可预期的,再加上ServiceTableImpl 自身的逻辑,会导致整个行为可能性变化太大,输出结果不可预期。而且测试的范围也从原来的 ServiceTableImpl 扩展到 ServiceTableImpl + ClientFactory + AppInfoDAO。
单元测试的目的在于测试一个局部的模块,在这里指的是 ServiceTableImpl,那么我们需要让 ClientFactory 和 AppInfoDAO的行为变得可预期,这样可以专心的测试ServiceTableImpl的内部逻辑,这才是单元测试!如何让 ClientFactory 和 AppInfoDAO 的行为变得可预期的呢,比如我需要让appInfoDAO.getAppInfoByMethod(method) 方法一定可以返回一个 serviceid, 让 referenceClient.getService(serviceId) 一定可以查找到一个服务呢?
这用到了Mock技术 - 创建一个虚假的 AppInfoDAO 实现,让它返回需要的结果。对于上面的例子可以继承 AppInfoDAO 并覆盖它的 getAppInfoByMethod 方法:
// 继承AppInfoDAO并覆盖getAppInfoByMethod方法,返回需要的结果
public class MockAppInfoDAO extends AppInfoDAO {
AppInfo getAppInfoByMethod(String method) {
AppInfo appInfo = new AppInfo();
appInfo.setServiceId("a service id");
return appInfo;
}
}
//把 MockAppInfoDAO 注入到ServiceTableImpl
ServiceTableImpl.setAppInfoDAO(new MockAppInfoDAO());
同样的道理可以Mock掉ClientFactory,如此便可以把 ServiceTableImpl 的依赖变得可控,这样可以单独的测试自己的内部逻辑了。
对于第三点,我以前是非常坚持的 - Android很难做单元测试。Android确实很难做单元测试,尤其是Android是有界面的,有界面的系统往往都不容做单元测试。但是这并不对,测试不好做,往往是代码写的不够好并且没有用到合适的测试工具。先看一个简单的例子:
public class ShortLifeMemoCache<T> implements CacheService<T> {
private static final long DEFAULT_TTL = 1L*60*60*1000;
/**
* 生存时间(Time to live),单位:毫秒
*/
private long ttl = DEFAULT_TTL;
private final Map<String, Value<T>> cache = new HashMap<String, Value<T>>();
@Override
public void put(String key, T t) {
long life = System.currentTimeMillis() + ttl;
cache.put(key, new Value<T>(t, life));
}
@Override
public T get(String key) {
Value<T> v = cache.get(key);
if (v != null){
if(v.getLife() > System.currentTimeMillis()) {
return v.getValue();
} else {
cache.remove(key);
}
}
return null;
}
@Override
public T remove(String key) {
return cache.remove(key).getValue();
}
@Override
public int size() {
return cache.size();
}
// 省略getter和setter方法
...
// 封装一个Value和一个时间戳,如果超时则丢弃
static class Value<T> {
// 生存时间
private long life;
// 真实的Value
private T t;
public Value() {}
public Value(T t, long life) {
setValue(t, life);
}
// 省略getter和setter方法
...
}
}
注1:上面这个例子实现了一个内存缓存,被缓存的K-V对在内存中多存活一个小时,超出一个小时后会认为缓存过期并从内存中移除。
注2:可能有同学会修改ttl值,把ttl设置成一个比较小的值,那么可以等待了,但是这样是非常脆弱的,处理临界值的时候容易出错
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
iOS单元测试mocha、chai、sinon和istanbul实现百分之百的单元测试覆盖率关于单元测试的总结及思考编写更好的Java单元测试的7个技巧Android单元测试框架Robolectric3.0介绍(一)使用Kiwi单元测试总结单元测试如此重要,为什么你不知道Python单元测试??使用装饰器实现测试跳过和预期故障对Controller的单元测试写好单元测试的10个技巧单元测试的重要性Angular单元测试系列??Component、Directive、Pipe 以及ServiceAndroid单元测试的整理提升单元测试体验的利器--Mockito使用总结iOS UnitTest单元测试Vue的单元测试探索(二)
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南