junit使用,包含常用注解说明、Assert
、Suite
、Ignore
、Parameterized
、rules
、自定义 rule
、Categories
、静态导入
定义测试方法
JUnit
使用注解将方法标记为测试方法并配置它们。下表概述了 JUnit
中 4.x
和 5.x
版本中最重要的注释。所有这些注释都可以用于方法。
注解 | 描述 |
---|---|
@Test |
将方法标识为测试方法 |
@Before |
在每次测试之前执行。它用于准备测试环境(例如,读取输入数据,初始化类)。 |
@After |
每次测试后执行。它用于清理测试环境(例如,删除临时数据、恢复默认值)。它还可以通过清理昂贵的内存结构来节省内存。 |
@BeforeClass |
在所有测试开始之前执行一次。它用于执行时间密集型活动,例如连接到数据库。使用此注释标记的方法需要定义为static与 JUnit 一起使用。 |
@AfterClass |
在所有测试完成后执行一次。它用于执行清理活动,例如,断开与数据库的连接。使用此注释注释的方法需要定义为static与 JUnit 一起使用。 |
@Ignore 或者 @Ignore("Why disabled") |
标记应禁用该测试。当底层代码已更改且测试用例尚未调整时,这很有用。或者如果这个测试的执行时间太长而无法包括在内。最佳做法是提供可选说明,说明为什么禁用测试。 |
@Test (expected = Exception.class) |
如果该方法不抛出指定的异常,则失败。 |
@Test(timeout=100) |
如果该方法花费的时间超过 100 毫秒,则失败。 |
断言
JUnit 提供静态方法来通过Assert类测试某些条件。这些断言语句通常以assert. 它们允许您指定错误消息、预期结果和实际结果。一个断言方法比较通过测试返回预期值实际值。AssertionException如果比较失败,它会抛出一个。
assert | 描述 |
---|---|
assertTrue([message,] boolean condition) |
检查布尔条件是否为真。 |
assertFalse([message,] boolean condition) |
检查布尔条件是否为假。 |
assertEquals([message,] expected, actual) |
测试两个值是否相同。注意:对于数组,检查引用而不是数组的内容。 |
assertEquals([message,] expected, actual, tolerance) |
测试 float 或 double 值是否匹配。容差是必须相同的小数位数。 |
assertNull([message,] object) |
检查对象是否为空。 |
assertNotNull([message,] object) |
检查对象是否为空。 |
assertSame([message,] expected, actual) |
检查两个变量是否指向同一个对象。 |
assertNotSame([message,] expected, actual) |
检查两个变量是否指向不同的对象。 |
测试套件
如果您有多个测试类,您可以将它们组合成一个测试套件。运行测试套件会按指定顺序执行该套件中的所有测试类。一个测试套件还可以包含其他测试套件。
以下示例代码演示了测试套件的用法。它包含两个测试类(MyClassTest 和 MySecondClassTest)。如果要添加另一个测试类,可以将其添加到@Suite.SuiteClasses语句中。
package com.vogella.junit.first;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
MyClassTest.class,
MySecondClassTest.class })
public class AllTests {
}
禁用测试
@Ignore 注释允许静态忽略测试。或者,您可以使用Assume.assumeFalse或Assume.assumeTrue来定义测试条件。 Assume.assumeFalse如果其条件评估为真,则将测试标记为无效。 Assume.assumeTrue如果条件评估为假,则将测试评估为无效。例如,以下在 Linux 上禁用测试:
Assume.assumeFalse(System.getProperty("os.name").contains("Linux"));
参数化测试
JUnit 允许您在测试类中使用参数。此类可以包含一个测试方法,并且使用提供的不同参数执行此方法。
您可以使用@RunWith(Parameterized.class)注释将测试类标记为参数化测试。
这样的测试类必须包含一个用@Parameters注解注解的静态方法。该方法生成并返回一个数组集合。此集合中的每一项都用作测试方法的参数。
您可以使用@Parameter公共字段上的注释来获取测试中注入的测试值。
以下代码显示了参数化测试的示例。出于本示例的目的,它测试作为内部类包含multiply()的MyClass类的方法。
package testing;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.runners.Parameterized.*;
@RunWith(Parameterized.class)
public class ParameterizedTestFields {
// fields used together with @Parameter must be public
@Parameter(0)
public int m1;
@Parameter(1)
public int m2;
@Parameter(2)
public int result;
// creates the test data
@Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1 , 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } };
return Arrays.asList(data);
}
@Test
public void testMultiplyException() {
MyClass tester = new MyClass();
assertEquals("Result", result, tester.multiply(m1, m2));
}
// class to be tested
class MyClass {
public int multiply(int i, int j) {
return i *j;
}
}
}
作为使用@Parameter注释的替代方法,您可以使用构造函数来存储每个测试的值。用注解的方法提供的每个数组中的元素数量 @Parameters 必须与类的构造函数中的参数数量相对应。为每个参数创建类,测试值通过构造函数传递给类。
package de.vogella.junit.first;
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 ParameterizedTestUsingConstructor {
private int m1;
private int m2;
public ParameterizedTestUsingConstructor(int p1, int p2) {
m1 = p1;
m2 = p2;
}
// creates the test data
@Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1 , 2 }, { 5, 3 }, { 121, 4 } };
return Arrays.asList(data);
}
@Test
public void testMultiplyException() {
MyClass tester = new MyClass();
assertEquals("Result", m1 * m2, tester.multiply(m1, m2));
}
// class to be tested
class MyClass {
public int multiply(int i, int j) {
return i *j;
}
}
}
如果您运行此测试类,则会使用每个定义的参数执行测试方法。在上面的例子中,测试方法被执行了 3 次。
rules
通过 JUnit 规则,您可以向测试类中的每个测试添加行为。您可以标注类型的字段TestRule与@Rule注释。您可以创建可以在测试方法中使用和配置的对象。这为您的测试增加了更多的灵活性。例如,您可以指定在执行测试代码期间期望的异常消息。
package de.vogella.junit.first;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class RuleExceptionTesterExample {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void throwsIllegalArgumentExceptionIfIconIsNull() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("Negative value not allowed");
ClassToBeTested t = new ClassToBeTested();
t.methodToBeTest(-1);
}
}
JUnit 已经提供了几个有用的规则实现。例如,TemporaryFolder该类允许设置在每次测试运行后自动删除的文件和文件夹。
以下代码显示了该TemporaryFolder实现的使用示例。
package de.vogella.junit.first;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class RuleTester {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File createdFolder = folder.newFolder("newfolder");
File createdFile = folder.newFile("myfilefile.txt");
assertTrue(createdFile.exists());
}
}
有关现有规则的更多示例,请参阅 Junit4 Rules
编写自定义rule
要编写自定义规则,您需要实现TestRule接口。此接口定义apply(Statement, Description)必须返回 的实例的方法Statement。Statement 表示 JUnit 运行时中的测试,而 Statement#evaluate() 运行这些测试。描述描述了单个测试。它允许通过反射读取有关测试的信息。
下面是一个简单的例子,用于在测试执行前后向 Android 应用程序添加日志语句。
package testing.android.vogella.com.asynctask;
import android.util.Log;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class MyCustomRule implements TestRule {
private Statement base;
private Description description;
@Override
public Statement apply(Statement base, Description description) {
this.base = base;
this.description = description;
return new MyStatement(base);
}
public class MyStatement extends Statement {
private final Statement base;
public MyStatement(Statement base) {
this.base = base;
}
@Override
public void evaluate() throws Throwable {
System.
Log.w("MyCustomRule",description.getMethodName() + "Started" );
try {
base.evaluate();
} finally {
Log.w("MyCustomRule",description.getMethodName() + "Finished");
}
}
}
}
要使用此规则,只需@Rule在您的测试类中添加一个注释字段即可。
@Rule
public MyCustomRule myRule = new MyCustomRule();
Categories 类别
可以定义测试类别并根据注释包含或排除它们。以下示例基于 JUnit 4.8 发行说明 。
public interface FastTests { /* category marker */
}
public interface SlowTests { /* category marker */
}
public class A {
@Test
public void a() {
fail();
}
@Category(SlowTests.class)
@Test
public void b() {
}
}
@Category({ SlowTests.class, FastTests.class })
public class B {
@Test
public void c() {
}
}
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@SuiteClasses({ A.class, B.class })
// Note that Categories is a kind of Suite
public class SlowTestSuite {
// Will run A.b and B.c, but not A.a
}
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@ExcludeCategory(FastTests.class)
@SuiteClasses({ A.class, B.class })
// Note that Categories is a kind of Suite
public class SlowTestSuite {
// Will run A.b, but not A.a or B.c
}
静态导入
静态导入是一种特性,它允许在public static不指定定义字段的类的情况下使用类中定义的字段和方法。
JUnit 断言语句通常被定义为public static允许开发人员编写简短的测试语句。以下代码段演示了带有和不带有静态导入的 assert 语句。
// without static imports you have to write the following statement
Assert.assertEquals("10 x 5 must be 50", 50, tester.multiply(10, 5));
// alternatively define assertEquals as static import
import static org.junit.Assert.assertEquals;
// more code
// use assertEquals directly because of the static import
assertEquals("10 x 5 must be 50", 50, tester.multiply(10, 5));