哈工大软件构造实验中JUnit的使用
防扒链接:
何以牵尘的博客_CSDN博客-哈工大课内学习,哈工大精品课程笔记领域博主何以牵尘擅长哈工大课内学习,哈工大精品课程笔记,等方面的知识https://blog.csdn.net/m0_61753302
关于哈工大软件构造实验中JUnit测试的使用说明
在哈工大软件构造实验Lab1和Lab2中我们已经接触到了JUnit单元测试,关于JUnit插件在IDEA中的应用已经在Lab1实验报告里有过详细讲解如何应用:
注意到JUnit的一些语句,如assertEqual、assertTrue等与上一篇博客assert语句有许多相近的地方:
因此,为了避免与assert断言相混淆,总结本篇博客来详细阐述JUnit的使用,同时也加入了关于复习软件构造课程中复习测试部分的心得总结(买一赠一,这不赚翻了doge~~~)
目录
1、单元测试
既然叫JUnit单元测试,那么何为单元测试呢?本菜狗遍历全网,找到如下解释:
- 在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试,。
- 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。
- 程序单元是应用的最小可测试部件。
- 简单来说,就是测试数据的稳定性是否达到程序的预期。
2、单元测试的重要性
对于我等哈工大计算机“优秀学子”,单元测试的重要性不言而喻——不用它实验就扣分了,这不比什么都重要(bushi)???
正经地说,单元测试的重要性在老师的PPT里有,老师在实验课里也反复强调,你要是还不懂重要性说明你没听课 (不懂活该)
3、黑盒测试与白盒测试
这也是PPT里的一个重点部分
3.1 黑盒测试
黑盒测试又称功能测试。它通过测试来检验程序是否能正常使用。在测试过程中,我们把程序看作为一个打不开的盒子,黑黑的什么也看不见,内部代码怎么写的也不知道。也就是说完全不考虑任何内部结构和性能的情况下为程序传入(Input)参数,然后去查看程序输出(Output)是否在正常范围内,通常这时候我们需要多此测试才得出结论。
特点: 不需要我们中间参与编写任何代码,传入参数值后查看程序是否正常或达到预期值。
3.2 白盒测试
白盒测试又称结构测试。在这里白盒测试与黑盒测试不同,在测试过程中,我们可以把程序看作为一个可以看到的白色透明盒子,我们清楚盒子内部的代码和结构。我们在使用白盒测试的时候,测试人员必须检查程序的内部结构,而要从检查程序的逻辑开始,一步一步的检查传入参数(Input)并查看程序的运行过程和输出(Output)结果,最终得出测试数据。这也就是“白盒测试”为什么叫穷举路径测试的原因,再次强调,是因为我们清楚程序的内部结构和代码,从而检查所有结构的正确与否和预期值。
注意: 单元测试就是白盒测试的一种!
4、单元测试的编码规范
- 类名: 定义测试类,类名是由被测试类名Test构成。例如:CalculatorTest
- 包名: 定义的测试类需要放在xxx.xxx.xxx.test包中。例如:package com.mylifes1110.test;
- 方法名: 测试方法的方法名有两种定义方式test测试方法和测试方法。例如:testAdd和add
- 返回值: 因为我们的方法只是在类中测试,可以独立运行,所以不需要处理任何返回值,所以这里使用void。例如:public void add();
- 参数列表: 因为我们的方法是用来测试的,至于参数列表的传入是没有必要的。我们在测试的时候自行传入需要的参数测试即可。所以在此参数列表为空。例如:例如:public void add();
- @Test注解: 测试是需要运行来完成的。如果我们只有一个main方法,显然在结构上还是需要我们去注释掉测试过的。解决此问题这里我们需要在测试方法上方加@Test注解来完成测试,只要是加该注解的方法,可以单独运行此方法来完成测试。
- jar包Junit4: @Test注解是需要我们导入jar包才能使用的。jar包有两个分别是:junit-4.13-rc-2和hamcrest-core-1.3。学校要求我们使用的是Junit4,单元测试还有Junit5。
- IDEA快捷导入Junit4: 使用IDEA的小伙伴,你们的福音来了,
谁让我用的就是IDEA呢。我们可以先创建测试类和方法,然后在测试方法上方加入@Test注解,此时IDEA显示的@Test注解是飘红的,这时候我们使用Alt + Enter组合键来打开导入Junit单元测试列表,然后再选择Junit4确定即可导入成功!这时候再查看注解就没有飘红了!
5、常用JUnit测试方法
assertEqual(a,b,[msg='测试失败时打印的信息']) // 断言a和b是否相等,相等则测试用例通过。
assertNotEqual(a,b,[msg='测试失败时打印的信息']) //断言a和b是否相等,不相等则测试用例通过。
assertTrue(x,[msg='测试失败时打印的信息']) //断言x是否True,是True则测试用例通过。
assertFalse(x,[msg='测试失败时打印的信息']) //断言x是否False,是False则测试用例通过。
assertIs(a,b,[msg='测试失败时打印的信息']) //断言a是否是b,是则测试用例通过。
assertNotIs(a,b,[msg='测试失败时打印的信息']) //断言a是否是b,不是则测试用例通过。
assertIsNone(x,[msg='测试失败时打印的信息']) //断言x是否None,是None则测试用例通过。
assertIsNotNone(x,[msg='测试失败时打印的信息']) //断言x是否None,不是None则测试用例通过。
assertIn(a,b,[msg='测试失败时打印的信息']) //断言a是否在b中,在b中则测试用例通过。
assertNotIn(a,b,[msg='测试失败时打印的信息']) //断言a是否在b中,不在b中则测试用例通过。
assertIsInstance(a,b,[msg='测试失败时打印的信息']) //断言a是是b的一个实例,是则测试用例通过。
assertNotIsInstance(a,b,[msg='测试失败时打印的信息']) //断言a是是b的一个实例,不是则测试用例通过。
这些方法都在
org.junit.Assert;
这个包里
注意:我们使用断言的时候尽量不要去断言Double对象。对于双精度数,绝对有必要使用增量进行比较,以避免浮点舍入的问题。如果您使用assertEquals
带有double
参数的3参数版本。
assertEquals(double expected, double actual, double delta);
这样一来Double
将被自动取消装箱,double
并且一切正常,测试结果就不会失败。否则使用两个参数的来断言double类型,会有如下报错信息:
使用浮点数时,由于浮点数无法精确地进行比较,因此,我们需要调用
assertEquals(double expected, double actual, double delta);
这个重载方法,指定一个误差值:
assertEquals(0.1, Math.abs(1 - 9 / 10.0), 0.0000001);
6、@Before和@After注解
- 我们在上述,你是否会发现有一些重复操作呢?比如,我们每一个方法都需要去new对象。有些聪明的小伙伴会说,我们可以把它提到类的里面与方法同级。对,这个处理方式也是一个正解。
- 但是我们在Junit单元测试中,有一个@Before注解,是用作资源的申请。也就是被@Before注解修饰的的方法会在测试方法之前自动执行。所以,我们可以去定义一个init方法,去初始化这个创建对象的过程。这就是@Before注解的作用!
- 有些应用场景,比如IO流的读写操作。如果我们要测试此代码,是需要一个关闭流的过程,通过我们关闭流使用finally块来保证最后流的关闭操作。这时,我们在Junit单元测试中,有一个@After注解,是用作资源的关闭。也就是说被@After注解修饰的方法会在测试方法之后自定执行。所以,我们在特定需要保证最后关闭、销毁资源的时候,可以去定义一个close方法,去关闭或销毁资源。这就是@After注解的作用!
- 注意: @Before和@After注解在程序报错的时候,仍然可以保证数据的初始化和关闭销毁,两个方法是依旧执行的。这里有点像我们tomact服务器的初始阶段和销毁阶段,它们的执行不受任何影响。