java单元测试JUnit框架原理与用法实例教程

网友投稿 579 2023-03-19


java单元测试JUnit框架原理与用法实例教程

本文实例讲述了java单元测试JUnit框架原理与用法。分享给大家供大家参考,具体如下:

1 简介

2 特点

JUnit提供了注释以及确定的测试方法;

JUnit提供了断言用于测试预期的结果;

JUnit测试优雅简洁不需要花费太多的时间;

JUnit测试让大家可以更快地编写代码并且提高质量;

JUnit测试可以组织成测试套件包含测试案例,甚至其他测试套件;

Junit显示测试进度,如果测试是没有问题条形是绿色的,测试失败则会变成红色;

JUnit测试可以自动运行,检查自己的结果,并提供即时反馈,没有必要通过测试结果报告来手动梳理。

3 内容

3.1 注解

@Test :该注释表示,用其附着的公共无效方法(即用public修饰的void类型的方法 )可以作为一个测试用例;

@Before :该注释表示,用其附着的方法必须在类中的每个测试之前执行,以便执行测试某些必要的先决条件;

@BeforeClass :该注释表示,用其附着的静态方法必须执行一次并在类的所有测试之前,发生这种情况时一般是测试计算共享配置方法,如连接到数据库;

@After :该注释表示,用其附着的方法在执行每项测试后执行,如执行每一个测试后重置某些变量,删除临时变量等;

@AfterClass :该注释表示,当需要执行所有的测试在JUnit测试用例类后执行,AfterClass注解可以使用以清理建立方法,如断开数据库连接,注意:附有此批注(类似于BeforeClass)的方法必须定义为静态;

@Ignore :该注释表示,当想暂时禁用特定的测试执行可以使用忽略注释,每个被注解为@Ignore的方法将不被执行。

/**

* JUnit 注解示例

*/

@Test

public void testYeepay(){

Syetem.out.println("用@Test标示测试方法!");

}

@AfterClass

public static void paylus(){

Syetem.out.println("用@AfterClass标示的方法在测试用例类执行完之后!");

}

3.2 断言

void assertEquals([String message], expected value, actual value) :断言两个值相等,值的类型可以为int、short、long、byte、char 或者

java.lang.Object,其中第一个参数是一个可选的字符串消息;

void assertTrue([String message], boolean condition) :断言一个条件为真;

void assertFalse([String message],boolean condition) :断言一个条件为假;

void assertNotNull([String message], java.lang.Object object) :断言一个对象不为空(null);

void assertNull([String message], java.lang.Object object) :断言一个对象为空(null);

void assertSame([String message], java.lang.Object expected, java.lang.Object actual) :断言两个对象引用相同的对象;

void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) :断言两个对象不是引用同一个对象;

void assertArrayEquals([String message], expectedArray, resultArray) :断言预期数组和结果数组相等,数组的类型可以为int、long、short、char、byte 或者 java.lang.Object

4 JUnit 3.X 和 JUnit 4.X 的区别

4.1 JUnit 3.X

(1)使用 JUnit 3.X 版本进行单元测试时,测试类必须要继承于 TestCase 父类;

(2)测试方法需要遵循的原则:

① public的;

② void的;

③ 无方法参数;

④方法名称必须以 test 开头;

(3)不同的测试用例之间一定要保持完全的独立性,不能有任何的关联;

(4)要掌握好测试方法的顺序,不能依赖于测试方法自己的执行顺序。

/**

* 用 JUnit 3.X 进行测试

*/

import junit.framework.Assert;

import junit.framework.TestCase;

public class TestOperation extends TestCase {

private Operation operation;

public TestOperation(String name) { // 构造函数

super(name);

}

@Override

public void setUp() throws Exception { // 在每个测试方法执行 [之前] 都会被调用,多用于初始化

System.out.println("欢迎使用Junit进行单元测试...");

operation = new Operation();

}

@Override

public void tearDown() throws Exception { // 在每个测试方法执行 [之后] 都会被调用,多用于释放资源

System.out.println("Junit单元测试结束...");

}

public void testDivideByZero() {

Throwable te = null;

try {

operation.divide(6, 0);

Assert.fail("测试失败"); //断言失败

} catch (Exception e) {

e.printStackTrace();

te = e;

}

Assert.assertEquals(Exception.class, te.getClass());

Assert.assertEquals("除数不能为 0 ", te.getMessage());

}

}

4.2 JUnit 4.X

(1)使用 JUnit 4.X 版本进行单元测试时,不用测试类继承TestCase父类;

(2)JUnit 4.X 版本,引用了注解的方式进行单元测试;

(3)JUnit 4.X 版本我们常用的注解包括:

@Before 注解:与JUnit 3.X 中的 setUp() 方法功能一样,在每个测试方法之前执行,多用于初始化;

@After 注解:与 JUnit 3.X 中的 tearDown() 方法功能一样,在每个测试方法之后执行,多用于释放资源;

@Test(timeout = xxx) 注解:设置当前测试方法在一定时间内运行完,否则返回错误;

@Test(expected = Exception.class) 注解:设置被测试的方法是否有异常抛出。抛出异常类型为:Exception.class;

此外,我们可以通过阅读上面的第二部分“2 注解”了解更多的注解。

/**

* 用 JUnit 4.X 进行测试

*/

import static org.junit.Assert.*;

import org.junit.After;

import org.junit.AfterClass;

import org.junit.Before;

import org.junit.BeforeClass;

import org.junit.Test;

public class TestOperation {

private Operation operation;

@BeforeClass

public static void globalInit() { // 在所有方法执行之前执行

System.out.println("@BeforeClass标注的方法,在所有方法执行之前执行...");

}

@AfterClass

public static void globalDestory() { // 在所有方法执行之后执行

System.out.println("@AfterClass标注的方法,在所有方法执行之后执行...");

}

@Before

public void setUp() { // 在每个测试方法之前执行

System.out.println("@Before标注的方法,在每个测试方法之前执行...");

operation = new Operation();

}

@After

public void tearDown() { // 在每个测试方法之后执行

System.out.println("@After标注的方法,在每个测试方法之后执行...");

}

@Test(timeout=600)

public void testAdd() { // 设置限定测试方法的运行时间 如果超出则返回错误

System.out.println("测试 add 方法...");

int result = operation.add(2, 3);

assertEquals(5, result);

}

@Test

public void testSubtract() {

System.out.println("测试 subtract 方法...");

int result = operation.subtract(1, 2);

assertEquals(-1, result);

}

@Test

public void testMultiply() {

System.out.println("测试 multiply 方法...");

int result = operation.multiply(2, 3);

http:// assertEquals(6, result);

}

@Test

public void testDivide() {

System.out.println("测试 divide 方法...");

int result = 0;

try {

result = operation.divide(6, 2);

} catch (Exception e) {

fail();

}

assertEquals(3, result);

}

@Test(expected = Exception.class)

public void testDivideAgain() throws Exception {

System.out.println("测试 divide 方法,除数为 0 的情况...");

operation.divide(6, 0);

fail("test Error");

}

public static void main(String[] args) {

}

}

4.3 特别提醒

/**

* 定义了加减乘除的法则

*/

public class Operation {

public static void main(String[] args) {

System.out.println("a + b = " + add(1,2));

System.out.println("a - b = " + subtract(1,2));

System.out.println("a * b = " + multiply(1,2));

System.out.println("a / b = " + divide(4,2));

System.out.println("a / b = " + divide(1,0));

}

public static int add(int a, int b) {

return a + b;

}

public static int subtract(int a, int b) {

return a - b;

}

public static int multiply(int a, int b) {

http://return a * b;

}

public static int divide(int a, int b) {

return a / b;

}

}

5 测试示例

5.1 示例一:简单的 JUnit 3.X 测试

import junit.framework.Test;

import junit.framework.TestCase;

import junit.framework.TestSuite;

import java.util.ArrayList;

import java.util.Collection;

/**

* 1、创建一个测试类,继承TestCase类

*/

public class SimpleTestDemo extends TestCase {

public SimpleTestDemo(String name) {

super(name);

}

/**

* 2、写一个测试方法,断言期望的结果

*/

public void testEmptyCollection(){

Collection collection = new ArrayList();

assertTrue(collection.isEmpty());

}

/**

* 3、写一个suite()方法,它会使用反射动态的创建一个包含所有的testXxxx方法的测试套件

*/

public static Test suit(){

return new TestSuite(SimpleTestDemo.class);

}

/**

* 4、写一个main()方法,以文本运行器的方式方便的运行测试

*/

public static void main(String[] args) {

junit.textui.TestRunner.run(suit());

}

}

5.2 示例二:套件测试

首先,介绍一下套件测试,简单来讲,测试套件是指:一些测试不同类的用例,可以使用 @RunWith 和 @Suite 注解把所有的测试类套在一起,从而形成测试套件。如果有很多测试类,想让它们都运行在同一时间,而不是单一地运行每个测试,套件测试是非常有用的。当一个类被注解为 @RunWith, JUnit 将调用其中的注解,以便运行测试类,而不使用内置的 JUnit 运行方法。

/**

* 待测试类

*/

import java.util.Arrays;

public class GotoWork {

public String[] prepareSkills() {

String[] skill = { "Java", "mysql", "jsP" };

System.out.println("My skills include : " + Arrays.toString(skill));

return skill;

}

public String[] addSkills() {

String[] skill = { "Java", "MySQL", "JSP", "JUnit" };

System.out.println("Look, my skills include : " + Arrays.toString(skill));

return skill;

}

}

/**

* 测试类 1

*/

import org.junit.Test;

import static org.junit.Assert.*;

public class PrepareSkillsTest {

GotoWork gotoWork = new GotoWork();

String[] skill = { "Java", "MySQL", "JSP" };

@Test

public void testPrepareSkills() {

System.out.println("Inside testPrepareSkills()");

assertArrayEquals(skill, gotoWork.prepareSkills());

}

}

/**

* 测试类 2

*/

import org.junit.Test;

import static org.junit.Assert.*;

public class AddSkillsTest {

GotoWork gotoWork = new GotoWork();

String[] skill = { "Java", "MySQL", "JSP", "JUnit" };

@Test

public void testAddSkills() {

System.out.println("Inside testAddPencils()");

assertArrayEquals(skill, gotoWork.addSkills());

}

}

/**

* 套件测试

*/

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

@RunWith(Suite.class)

@Suite.SuiteClasses({ PrepareSkillsTest.class, AddSkillsTest.class })

public class SuitTest {

}

使用 @Suite.SuiteClasses 注解,可以定义测试类,将被列入执行,并且执行的顺序就是在 @Suite.SuiteClasses 注解中定义的顺序。

5.3 示例三:参数化测试

首先介绍一下参数化测试,一个测试类可以被看作是一个参数化测试类,当其满足下列所有要求:

① 该类被注解为 @RunWith(Parameterized.class);

② 该类有一个构造函数,存储测试数据;

③ 该类有一个静态方法生成并返回测试数据,并标注 @Parameters 注解;

④ 该类有一个测试方法,即用注解 @Test 标注的方法。

/**

* 待测试类

*/

public class Calculate {

public int sum(int var1, int var2) {

System.out.println("此方法的参数值分别为 : " + var1 + " + " + var2);

return var1 + var2;

}

}

/**

* 参数化测试类

*/

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import java.util.Collection;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)

public class CalculateTest {

private int expected;

private int first;

private int second;

public CalculateTest(int expectedResult, int firstNumber, int secondNumber) {

this.expected = expectedResult;

this.first = firstNumber;

this.second = secondNumber;

}

@Parameters

public static Collection addedNumbers() {

return Arrays.asList(new Integer[][] { { 3, 1, 2 }, { 5, 2, 3 }, { 7, 3, 4 }, { 9, 4, 5 }, });

}

@Test

public void testSum() {

Calculate add = new Calculate();

System.out.println("Addition with parameters : " + first + " and " + second);

assertEquals(expected, add.sum(first, second));

}

}

观察 CalculateTest 类,它满足上述所有的要求,因此它就可以称为一个参数化测试类。addedNumbers 方法使用注释 @Parameters 返回数组的集合,每个数组包括每个测试执行输入和输出数字,每个数组中的元素数必须相同好与构造参数的个数相匹配。所以,在这种特定的情况下,每个数组包括三个元素,即表示要加入的两个元素和一个结果元素。

6 个人建议

有些童鞋可能会有一些误解,认为写测试代码没有用,而且还会增大自己的压力,浪费时间。但事实上,写测试代码与否,还是有很大区别的,如果是在小的项目中,或许这种区别还不太明显,但如果在大型项目中,一旦出现错误或异常,用人力去排查的话,那将会浪费很多时间,而且还不一定排查的出来,但是如果用测试代码的话,JUnit 就是自动帮我们判断一些代码的结果正确与否,从而节省的时间将会远远超过你写测试代码的时间。

1. 不要用 TestCase 的构造函数初始化 Fixture,而要用 setUp() 和 tearDown() 方法;

2. 不要依赖或假定测试运行的顺序,因为 JUnit 会利用 Vector 保存测试方法,所以不同的平台会按不同的顺序从 Vector 中取出测试方法;

3. 避免编写有副作用的 TestCase,例如:如果随后的测试依赖于某些特定的交易数据,就不要提交交易数据,只需要简单的回滚就可以了;

4. 当继承一个测试类时,记得调用父类的 setUp() 和 tearDown() 方法;

5. 将测试代码和工作代码放在一起,同步编译和更新;

6. 测试类和测试方法应该有一致的命名方案,如在工作类名前加上 test 从而形成测试类名;

7. 确保测试与时间无关,不要使用过期的数据进行测试,以至于导致在随后的维护过程中很难重现测试;

8. 如果编写的软件面向国际市场,那么编写测试时一定要考虑国际化的因素;

9. 尽可能地利用 JUnit 提供地 assert 和 fail 方法以及异常处理的方法,其可以使代码更为简洁;

10. 测试要尽可能地小,执行速度快;

11. 不要硬性规定数据文件的路径;

12. 使用文档生成器做测试文档。

事实上,在 Junit 中使用 try catch 来捕获异常是没有必要的,因为 Junit 会自动捕获异常,那些没有被捕获的异常就会被当成错误处理啦!

更多关于java相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java字符与字符串操作技巧总结》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:api接口文档都有哪些(api接口文档示例)
下一篇:关于tcp接口性能测试用例的信息
相关文章

 发表评论

暂时没有评论,来抢沙发吧~