单元测试我的理解
- 软件质量保障体系中的一个重要概念,最早发现错误是最节省成本的一种情况。
- 单元测试带给我们程序员的是一种思维方式的改变,我们不仅是功能实现者我们还是使用者
- 单元测试是控制软件质量非常有效的方法,单元测试工程是软件系统后期维护和扩展的基础
- 单元测试代码要比单纯的软件API有用的多
- 站在单元测试的角度“一切都应当产出预计的结果”
单元测试的目的
- 提高软件质量
- 过早暴露问题
- 可作为软件系统后期维护的基准
- 代码文档化
- 请思考当我们修改了一段代码后,我们如何保证它是可以正常使用的?
- 代码耦合过高
- 代码自身逻辑复杂
- 代码自身规模很大
单元测试的好处
- 软件生产率的提升
- 降低错误出现机率
- 辅助错误复现和排查
- 辅助代码扩展、二次开发
实施单元测试要考量
- 开发效率
- 时间成本
- 要维护的代码变多了
- 单元测试没有意义
- 测试用例也需要维护
- 做单元测试并不轻松
- 频繁的需求变更
- 代码结构设计不利于测试
- 高标准的覆盖率
单元测试方法
测试驱动
可以将测试驱动理解为一种单元测试的应用场景,测试驱动的内在动机就是让测试遍布在编码的每个阶段,从问题被定义后就开始考虑测试。
测试驱动的简要流程
- 分析定义问题
- 使用代码描述问题,编写单元测试
- 使用代码解决问题,保证测试通过
- 重构编写的代码,使用单元测试保驾护航
测试驱动目标
- 利用测试驱动业务目标的实现
- 确保逻辑单元正确
- 及时和快速的定位问题
离我们很近的辅助测试工具
- JUnit,当前我们公司部分软件产品使用的JUnit3
- TestNG,比JUnit年轻拥有比JUnit灵活的一些功能特色,它与JUnit也算是互相促进的关系。
单元测试实践
JUnit3非常经典但相比JUnit4它的限制要求有很多这样就会增加我们不必要的编码,当然也就非常的不够人性化了,所以我们可以直接考虑升级到JUnit4,但这也只限于在JDK1.5之上构建的软件系统。
- Eclipse集成有JUnit
- JUnit4常用注解
描述 | 备注 |
@BeforeClass | 全局测试用例加载前调用 |
@AfterClass | 全局测试用例完成后调用 |
@Before | 各测试方法运行前调用 |
@After | 各测试方法运行后调用 |
@Test | 标识测试执行方法 |
@ignore | 忽略测试执行 |
@RunWith | Runner选择 |
JUnit核心Runner结构
- JUnit4用例代码结构
public class TaskMgrTest {
private Connection conn;
private TaskMgr taskMgrInst;
private String connURL;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Before
public void setUp() throws Exception {
this.connURL = "jdbc:oracle:thin:SCOTT/TIGER@127.0.0.1:1521/orcl";
this.conn = DBUtils.createConn4Oracle(connURL);
taskMgrInst = new TaskMgr();
taskMgrInst.setConn(this.conn);
}
@After
public void tearDown() throws Exception {
DBUtils.close(this.conn);
}
@Test
public void testAddTask() {
Task taskInst = new Task("任务1", "任务1的描述");
try {
Assert.assertTrue(taskMgrInst.addTask(taskInst));
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test(expected=SQLException.class)
public void testAddTaskException() throws SQLException {
Task taskInst = new Task("", "");
try {
taskMgrInst.addTask(taskInst);
} catch (SQLException e) {
throw e;
}
}
}
- 寻找示例
- 开源社区中非常多优秀的开源软件都包含了大量的单元测试用例,在不知道如何入手的情况下学习现存的经验算是捷径.
单元测试自动化
- 扩展JUnit,JUnit自向设计的就非常优秀,我们可以在分析清楚自身需求的情况下对JUnit功能进行扩展。
- JUnit与Ant,Ant作为一款非常棒的自动化构建工具它当然也有JUnit的支持了,可以通过针对JUnit的Ant任务来批量执行基于JUnit的单元测试用例并生成报表。
示例
<target name="testunit">
<echo message="Running TestCase Begin" />
<junit printsummary="on" fork="true" showoutput="true">
<classpath refid="project.compile.lib" />
<classpath refid="project.compile.testlib" />
<formatter type="xml" />
<batchtest todir="${project.junit.output}">
<fileset dir="${project.build.tmpdir}">
<patternset refid="project.junit.exclude" />
</fileset>
</batchtest>
</junit>
<echo message="Running TestCase End" />
</target>
<target name="report" depends="testunit">
<echo message="Report Begin" />
<junitreport todir="${project.junit.output}">
<fileset dir="${project.junit.output}">
<include name="TEST-*.xml" />
</fileset>
<report todir="${project.junit.output}" format="frames" />
</junitreport>
<echo message="Report End" />
</target>
随处可见的单元测试
首先,我们N9系统的技术设计结构非常的优秀,和普通的J2EE结构的项目结构相比,它的结构直接分离了与web呈现的耦合,这样它可以完全支持我们进行单元测试而不需要我们考虑太多关于web方面的模拟。
在我们的N9系统中存在有大量的单元测试用例,通过对这些单元测试的学习可以让我们轻松编写出适合我们自己风格的单元测试。
示例
柜面业务系统的结息事件发布,我们柜面系统每次结息后都要求将结息结果发送给EBD供其它与此相关的系统(比如信贷系统)使用。
参考类 |
|
| com.nstc.cpm.server.TestSendInterestEventToEBD |
| com.nstc.cpm.server.TestSendFBCMEventToEBD |
执行环境
1、后台服务必须能正常访问,通过Web浏览器输入http://127.0.0.1:6001/SMS-Service/main.service。
2、后台服务必须得有EBD模块。
图示_01
确认后台服务状态是否正常,出现如下界面说明我们后台服务状态是正常的,因为我们未传递其它参数所以会有Error 500异常。
图示_02
执行单元测试用例
观察执行结果
请尝试分析以下问题
1、结息事件所传递的内容仅能满足当前业务需要,在今后的时间里我们需要将结息类型标记、结息金额汇总等其它需求内容加入,这时我们要做什么?
2、在该功能发布的某一天现场给电话说结息传递的内容不对呀,现场柜面系统结的息是10.99元,EBD系统那里也是10.99元,但是其它业务子系统收到的怎么是11元?
3、在某此时刻测试人员给我们的Bug是不是总需要排查和复现问题,我们是不是又要重新做一条业务数据,有好些次听到测试人员说做一条测试数据不是一件容易的事情。
如何实施单元测试
- 掌握好我们的目标,单元测试只是一种促进我们工作方法的手段,不要为了单元测试而做单元测试。
- 给自己定一个小计划,从简单的实践入手循序渐进的掌握这种思想和方法。
- 需要坚持但要注意不要被单元测试所累。