Fork me on GitHub

这是一份简短的实践指南,向您展示使用 JUnit 编写和组织您自己的测试的步骤。

简单的测试用例

如何编写测试代码?

最简单的方法是在调试器中作为表达式。 您可以更改调试表达式而无需重新编译,并且可以在看到正在运行的对象后决定编写什么。 您还可以将测试表达式编写为打印到标准输出流的语句。 这两种测试风格都有局限性,因为它们需要人工判断来分析其结果。 此外,它们不能很好地组合 - 您一次只能执行一个调试表达式,并且包含太多打印语句的程序会导致可怕的“滚动盲”。

JUnit 测试不需要人工判断来解释,并且可以轻松地同时运行许多测试。 当您需要测试某些内容时,请执行以下操作

  1. 使用以下内容注解一个方法@org.junit.Test

  2. 当您要检查一个值时,导入org.junit.Assert.*静态地,调用assertTrue()并传递一个布尔值,如果测试成功,则该值为 true

例如,要测试两个具有相同货币的 Money 的总和是否包含一个值,该值是两个 Money 的值的总和,请编写

@Test
public void simpleAdd() {
    Money m12CHF= new Money(12, "CHF");
    Money m14CHF= new Money(14, "CHF");
    Money expected= new Money(26, "CHF");
    Money result= m12CHF.add(m14CHF);
    assertTrue(expected.equals(result));
}

如果您想编写一个类似于您已经编写的测试,请编写一个 Fixture 代替。

Fixture(测试夹具)

如果您有两个或多个测试在相同或相似的对象集上运行怎么办?

测试需要在已知对象集的背景下运行。 这组对象称为测试夹具。 当您编写测试时,您通常会发现您花费更多时间编写代码来设置夹具,而不是实际测试值。

在某种程度上,通过仔细注意您编写的构造函数,您可以使编写夹具代码更容易。 然而,更大的节省来自于共享夹具代码。 通常,您可以为几个不同的测试使用相同的夹具。 每种情况都会向夹具发送略有不同的消息或参数,并将检查不同的结果。

当您有一个公共夹具时,请执行以下操作

  1. 为夹具的每个部分添加一个字段
  2. 使用以下内容注解一个方法@org.junit.Before并在该方法中初始化变量
  3. 使用以下内容注解一个方法@org.junit.After以释放您在其中分配的任何永久资源setUp

例如,要编写几个想要使用 12 瑞士法郎、14 瑞士法郎和 28 美元的不同组合的测试用例,首先创建一个夹具

public class MoneyTest {
    private Money f12CHF;
    private Money f14CHF;
    private Money f28USD;

    @Before public void setUp() {
        f12CHF= new Money(12, "CHF");
        f14CHF= new Money(14, "CHF");
        f28USD= new Money(28, "USD");
    }
}

一旦您有了 Fixture,您就可以根据需要编写任意数量的测试用例。 添加任意数量的测试方法(使用@Test注解)即可。

运行测试

如何运行测试并收集其结果?

一旦您有了测试,您就会想要运行它们。 JUnit 提供了工具来定义要运行的套件并显示其结果。 要运行测试并在控制台上查看结果,请从 Java 程序运行此代码

org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);

或者从命令行运行此代码,将您的测试类和 junit 都放在类路径中

java org.junit.runner.JUnitCore TestClass1.class [...other test classes...]

您可以使您的 JUnit 4 测试类可以被设计用于早期版本 JUnit 的 TestRunner 访问,声明一个返回测试的静态方法 suite

public static junit.framework.Test suite() {
    return new JUnit4TestAdapter(Example.class);
}

预期异常

如何验证代码是否按预期抛出异常?

验证代码是否正常完成只是编程的一部分。 确保代码在异常情况下按预期运行也是编程技巧的一部分。 例如

new ArrayList<Object>().get(0);

此代码应抛出IndexOutOfBoundsException@Test注解有一个可选参数expected,它将Throwable的子类作为值。如果我们想验证ArrayList

@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
    new ArrayList<Object>().get(0);
}