可测试性
在设计软件时,要想一下这个函数/模块/系统要怎么测,当用这些标准去衡量系统时,可能会发现设计根本没有考虑过设计,这样,系统常常只有最外层的接口可以测试,即整个系统必须集成起来才能测试。所以在设计的时候,必须将可测试性纳入考量,以便于能够完成不同层次的测试,减少对集成环境的依赖。
步骤:
1.尽可能每个模块做更多的测试,使构成系统的每个模块尽可能稳定,把继承测试环境更多的留做公共的验收资源
2.尽可能搭建本地的集成测试环境,周边的系统可以采用模拟服务的方案。
在软件开发中考虑测试,实际上是思考软件质量的问题,把质量问题的思考前移到开发,甚至设计阶段,是软件开发从传统进入到现在的关键。
编写可测试性代码的原则:
1,分离不确定输入
案例1:判断闰年
public boolean isLeapYear() {
Date date = new Date();
int year = 1900 + date.getYear();
return year % 4 == 0;
}
以上方法的可测试性非常差,因为它依赖了一个固定的当前时间,如果要测试未来的时间,那就只能去等待
改进:
public boolean isLeapYear(int year) {
return year % 4 == 0;
}
2.面向抽象编程(这是编写可测试代码的基础)
案例2:
在开发一个爬虫程序,爬取拼多多的商品信息,如果发现返回失败,重试3次,每次间隔10秒,如果是一个初级开发者,可能会直接用new创建一个HttpClient这样的代码,但当验证访问时,是否会重试3次,且每次间隔10秒,这时,编写单元测试是非常困难的,当你发现使用了new很难测试的时候,就要考虑使用抽象的接口来替换了。
编写单元测试的技巧
案例3:
@Service
public class UserService{
@Autowired
private IUserDao userDao;
public void save(User user) {
userDao.insert(user,id, user.firstName + " " + user.lastName);
}
}
几个设问
1.单元测试测什么?是为了验证类的行为是否符合预期
2.如何处理依赖的行为不符合预期的情况?正常工作的情况下,被测试类能正常工作,类的所以依赖都是正确的。
3.如果在运行单元测试时,启动spring容器和数据库?单元测试不能启动spring和数据库,这是继承测试要做的、
测试过程
1.创建被测试对象
UserService userService = new UserService();
2.创建mock对象
IUserDao mockDao = mock(IUserDao.class);
3.对假对象进行打桩
when(mockDao).insert(anyString(), anyString()).doNothing();
4.对假对象进行断言
userService.save(new User(“123”, “hello”, “world”));
verify(mockDao).insert(eq("123), eq(hello world));