JUnit4教程

本文深入解析JUnit自动化测试框架,涵盖其特点、版本历史、注解使用、断言方法、测试套件创建、参数化测试及规则应用。通过实例演示,帮助读者掌握JUnit在Java单元测试中的实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JUnit介绍,JUnit是什么?

JJUnit是用于编写和运行可重复的自动化测试的开源测试框架, 这样可以保证我们的代码按预期工作。JUnit可广泛用于工业和作为支架(从命令行)或IDE(如Eclipse)内单独的Java程序。

JUnit提供:

  • 断言测试预期结果。
  • 测试功能共享通用的测试数据。
  • 测试套件轻松地组织和运行测试。
  • 图形和文本测试运行。

JUnit用于测试:

  • 整个对象
  • 对象的一部分 - 交互的方法或一些方法
  • 几个对象之间的互动(交互)

 

JUnit的特点

  • JUnit是用于编写和运行测试的开源框架。

  • 提供了注释,以确定测试方法。

  • 提供断言测试预期结果。

  • 提供了测试运行的运行测试。

  • JUnit测试让您可以更快地编写代码,提高质量

  • JUnit是优雅简洁。它是不那么复杂以及不需要花费太多的时间。

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

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

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

JUnit的版本

 2016/2    5.0内测版本

2017/11   5.0第一个正式版本

当前最新5.3.2

junit4已经发布了10多年   最新版本为4.12

JUnit注解

在本节中,我们将提到支持在JUnit4基本注释,下表列出了这些注释的概括:

注解描述
@Test
public void method()
测试注释指示该公共无效方法它所附着可以作为一个测试用例。
@Before
public void method()
Before注释表示,该方法必须在类中的每个测试之前执行,以便执行测试某些必要的先决条件。
@BeforeClass
public static void method()
BeforeClass注释指出这是附着在静态方法必须执行一次并在类的所有测试之前。发生这种情况时一般是测试计算共享配置方法(如连接到数据库)。
@After
public void method()
After 注释指示,该方法在执行每项测试后执行(如执行每一个测试后重置某些变量,删除临时变量等)
@AfterClass
public static void method()
当需要执行所有的测试在JUnit测试用例类后执行,AfterClass注解可以使用以清理建立方法,(从数据库如断开连接)。注意:附有此批注(类似于BeforeClass)的方法必须定义为静态。
@Ignore
public static void method()
当想暂时禁用特定的测试执行可以使用忽略注释。每个被注解为@Ignore的方法将不被执行。

 
让我们看看一个测试类,在上面提到的一些注解的一个例子。

AnnotationsTest.java

package com.yiibai.junit;

import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;

public class AnnotationsTest {

	private ArrayList testList;

	@BeforeClass
	public static void onceExecutedBeforeAll() {
		System.out.println("@BeforeClass: onceExecutedBeforeAll");
	}

	@Before
	public void executedBeforeEach() {
		testList = new ArrayList();
		System.out.println("@Before: executedBeforeEach");
	}

	@AfterClass
	public static void onceExecutedAfterAll() {
		System.out.println("@AfterClass: onceExecutedAfterAll");
	}

	@After
	public void executedAfterEach() {
		testList.clear();
		System.out.println("@After: executedAfterEach");
	}

	@Test
	public void EmptyCollection() {
		assertTrue(testList.isEmpty());
		System.out.println("@Test: EmptyArrayList");

	}

	@Test
	public void OneItemCollection() {
		testList.add("oneItem");
		assertEquals(1, testList.size());
		System.out.println("@Test: OneItemArrayList");
	}

	@Ignore
	public void executionIgnored() {

		System.out.println("@Ignore: This execution is ignored");
	}
}

如果我们运行上面的测试,控制台输出将是以下几点:

@BeforeClass: onceExecutedBeforeAll
@Before: executedBeforeEach
@Test: EmptyArrayList
@After: executedAfterEach
@Before: executedBeforeEach
@Test: OneItemArrayList
@After: executedAfterEach
@AfterClass: onceExecutedAfterAll

JUnit断言

在本节中,我们将介绍一些断言方法。所有这些方法都受到 Assert 类扩展了java.lang.Object类并为它们提供编写测试,以便检测故障。下表中有一种最常用的断言方法的更详细的解释。

断言描述
void assertEquals([String message], expected value, actual value)断言两个值相等。值可能是类型有 int, short, long, byte, char or 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 or java.lang.Object.

 让我们看的一些前述断言的一个例子。

AssertionsTest.java

package com.yiibai.junit;

import static org.junit.Assert.*;
import org.junit.Test;

public class AssertionsTest {

	@Test
	public void test() {
		String obj1 = "junit";
		String obj2 = "junit";
		String obj3 = "test";
		String obj4 = "test";
		String obj5 = null;
		int var1 = 1;
		int var2 = 2;
		int[] arithmetic1 = { 1, 2, 3 };
		int[] arithmetic2 = { 1, 2, 3 };

		assertEquals(obj1, obj2);

		assertSame(obj3, obj4);

		assertNotSame(obj2, obj4);

		assertNotNull(obj1);

		assertNull(obj5);

		assertTrue(var1  var2);

		assertArrayEquals(arithmetic1, arithmetic2);
	}

}

在以上类中我们可以看到,这些断言方法是可以工作的。

  •  assertEquals() 如果比较的两个对象是相等的,此方法将正常返回;否则失败显示在JUnit的窗口测试将中止。
  •  assertSame() 和 assertNotSame() 方法测试两个对象引用指向完全相同的对象。
  •  assertNull() 和 assertNotNull() 方法测试一个变量是否为空或不为空(null)。
  •  assertTrue() 和 assertFalse() 方法测试if条件或变量是true还是false。
  •  assertArrayEquals() 将比较两个数组,如果它们相等,则该方法将继续进行不会发出错误。否则失败将显示在JUnit窗口和中止测试。

使用@Ignore注解

断续上一节的例子,了解如何使用@Ignore注解。在测试类FirstDayAtSchoolTest中,我们将添加@Ignore注解到testAddPencils()方法。以这种方式,我们期望这个测试方法将被忽略,不被执行。

package com.yiibai.junit;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;

public class FirstDayAtSchoolTest {

	FirstDayAtSchool school = new FirstDayAtSchool();
	String[] bag1 = { "Books", "Notebooks", "Pens" };
	String[] bag2 = { "Books", "Notebooks", "Pens", "Pencils" };

	@Test
	public void testPrepareMyBag() {
		System.out.println("Inside testPrepareMyBag()");
		assertArrayEquals(bag1, school.prepareMyBag());
	}

	@Ignore
	@Test
	public void testAddPencils() {
		System.out.println("Inside testAddPencils()");
		assertArrayEquals(bag2, school.addPencils());
	}

}

事实上,这输出会发生什么:

Inside testPrepareMyBag()
My school bag contains: [Books, Notebooks, Pens]

现在,我们将从testAddPencils()方法去除@Ignore注解,修改为注释整个类来代替。

package com.yiibai.junit;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;

@Ignore
public class FirstDayAtSchoolTest {

	FirstDayAtSchool school = new FirstDayAtSchool();
	String[] bag1 = { "Books", "Notebooks", "Pens" };
	String[] bag2 = { "Books", "Notebooks", "Pens", "Pencils" };

	@Test
	public void testPrepareMyBag() {
		System.out.println("Inside testPrepareMyBag()");
		assertArrayEquals(bag1, school.prepareMyBag());
	}

	
	@Test
	public void testAddPencils() {
		System.out.println("Inside testAddPencils()");
		assertArrayEquals(bag2, school.addPencils());
	}

}

 

在这个测试类将不会执行,因此不显示在控制台和JUnit视图输出结果:

 

 

创建套件测试

在本节中,我们将学习如何创建套件测试。测试套件是一些测试不同类用例,可以使用@RunWith和@Suite注解运行所有东西在一起。如果有很多测试类,想让它们都运行在同一时间,而不是单一地运行每个测试,这是非常有用的。

当一个类被注解为@RunWith, JUnit 将调用被在其中注解,以便运行测试类,而不使用内置的 JUnit 运行方法。

基于前面的章节中的类,我们可以创建两个测试类。一个类将测试公共方法 prepareMyBag()和其他测试类将测试方法 addPencils()。因此,我们最终将有以下两个类:

PrepareMyBagTest.java

package com.yiibai.junit;

import org.junit.Test;
import static org.junit.Assert.*;

public class PrepareMyBagTest {

	FirstDayAtSchool school = new FirstDayAtSchool();

	String[] bag = { "Books", "Notebooks", "Pens" };

	@Test
	public void testPrepareMyBag() {

		System.out.println("Inside testPrepareMyBag()");
		assertArrayEquals(bag, school.prepareMyBag());

	}

}

AddPencilsTest.java

package com.yiibai.junit;

import org.junit.Test;
import static org.junit.Assert.*;

public class AddPencilsTest {

	FirstDayAtSchool school = new FirstDayAtSchool();

	String[] bag = { "Books", "Notebooks", "Pens", "Pencils" };

	@Test
	public void testAddPencils() {

		System.out.println("Inside testAddPencils()");
		assertArrayEquals(bag, school.addPencils());

	}

}

现在,我们将创建一个测试套件,以便运行上面的类在一起。用鼠标右键单击 test 源文件夹,并创建一个新的名为SuiteTest.java 的Java类,使用下面的代码:

SuiteTest.java

package com.yiibai.junit;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({ PrepareMyBagTest.class, AddPencilsTest.class })
public class SuitTest {

}

使用@ Suite.SuiteClasses注解,你可以定义测试类,将被列入执行。

所以,如果用鼠标右键单击测试套件并选择 Run As -> JUnit Test, 两个测试类与已经在@ Suite.SuiteClasses注解定义的顺序执行。

创建参数化测试

在本节中,我们将学习如何创建参数测试。为此,我们将使用前面章节中提供的一个公共方法添加整数。因此,这是要进行的测试类。

但是,一个测试类也可以被看作是一个参数化测试类?当然,但它要满足下列所有要求:

  • 该类被注解为 @RunWith(Parameterized.class).
    如前一节中所说明的, @RunWith 注解让JUnit来调用其中的注释来运行测试类,代替使用内置的JUnit运行器,Parameterized 是一个在JUnit内的运行器将运行相同的测试用例组在不同的输入。
  • 这个类有一个构造函数,存储测试数据。
  • 这个类有一个静态方法生成并返回测试数据,并注明@Parameters注解。
  • 这个类有一个测试,它需要注解@Test到方法。

现在,我们将创建一个名为 CalculateTest.java 的一个新的测试类, 遵循上述指导原则。这个类的源代码如下。

CalculateTest.java

package com.yiibai.junit;

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 sum() {
		Calculate add = new Calculate();
		System.out.println("Addition with parameters : " + first + " and "
				+ second);
		assertEquals(expected, add.sum(first, second));
	}
}

正如我们观察上面的类,它满足上述所有要求。addedNumbers方法使用注释@Parameters返回数组的集合。每个数组包括每个测试执行输入/输出数字。每个数组中的元素数必须相同以在构造参数的数目。所以,在这种特定的情况下,每个数组包括三个元素,即表示要加入的数字两个元素和一个元素结果。

如果我们运行 CalculateTest 测试用例,控制台输出如下:

Addition with parameters : 1 and 2
Adding values: 1 + 2
Addition with parameters : 2 and 3
Adding values: 2 + 3
Addition with parameters : 3 and 4
Adding values: 3 + 4
Addition with parameters : 4 and 5
Adding values: 4 + 5

正如我们在输出中看到,测试用例被执行4次,这是在方法的输入注解为@Parameters的数量。

JUnit规则

在本节中,我们学习和了解JUnit中叫做规则的新功能,它允许非常灵活在测试类重新定义每个测试方法的行为。为了这个目的,@Rule注解被使用来标出测试类的公共字段。这些字段类型为MethodRule,这是测试方法如何运行并报告。多个MethodRules可以应用到一个测试方法。MethodRule接口有很多的实现,如ErrorCollector在发现了第一个问题之后,也允许继续执行一个测试,ExpectedException 允许在测试规范预期的异常类型和消息,TestName 使得目前的测试名称在测试方法内部可用,以及其他许多。除了那些已经定义的规则,开发人员可以创建自己的自定义规则,并使用来测试自己用例。

下面我们介绍方法,可以使用一个名为TestName,在我们自己现有的测试规则。 TestName被调用在测试开始时。

 

NameRuleTest.java

package com.javacodegeeks.junit;

import static org.junit.Assert.*;

import org.junit.*;
import org.junit.rules.TestName;

public class NameRuleTest {
	@Rule
	public TestName name = new TestName();

	@Test
	public void testA() {
		System.out.println(name.getMethodName());
		assertEquals("testA", name.getMethodName());

	}

	@Test
	public void testB() {
		System.out.println(name.getMethodName());
		assertEquals("testB", name.getMethodName());
	}
}

我们可以看到,@Rule注解标记的类型是MethodRule的公共字段名,具体而言是TestName类型。 然后,可以在我们的测试中,这名称字段使用和查找,例如测试方法的名称,这种特定情况。

在命令行中运行JUnit测试

可以在Eclipse之外运行JUnit测试,使用org.junit.runner.JUnitCore类。 这个类提供了runClasses()方法,它允许运行一个或多个测试类。runClasses()方法返回类型是org.junit.runner.Result对象类型。 这个对象可以被用来收集关于测试信息。此外,如果有一个失败的测试,可以用org.junit.runner.notification.Failure对象保存失败测试的描述。

下面的步骤显示了如何在Eclipse之外(命令行下)运行测试。

用下面的代码创建一个新的Java类为JunitRunner.java:

JunitRunner.java

 

package com.yiibai.junit;

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class JunitRunner {

	public static void main(String[] args) {

		Result result = JUnitCore.runClasses(AssertionsTest.class);
		for (Failure fail : result.getFailures()) {
			System.out.println(fail.toString());
		}
		if (result.wasSuccessful()) {
			System.out.println("All tests finished successfully...");
		}
	}
}

 

作为一个例子,我们选择运行AssertionsTest测试类。

1C:\Users\yiibai\eclipse_workspace\JUnitGuide\test\com\yiibai\junit>javac -classpath "C:\Users\yiibai\Downloads\junit-4.11.jar";"C:\Users\yiibai\Downloads\hamcrest-core-1.3.jar"; AssertionsTest.java JunitRunner.java

注:这里指定包含相关 junit 的相关 jar 包。

1C:\Users\yiibai\eclipse_workspace\JUnitGuide\test\com\yiibai\junit>java -classpath "C:\Users\yiibai\Downloads\junit-4.11.jar";"C:\Users\yiibai\Downloads\hamcrest-core-1.3.jar"; JunitRunner
  • 打开命令提示符,然后往下移目录,找到两个类所在的目录。
  • 编译测试类和运行类。
  • 现在运行 JunitRunner.

这里是结果输出:

All tests finished successfully...
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值