Junit用法

2021-07-01
halley.fang

junit使用,包含常用注解说明、AssertSuiteIgnoreParameterizedrules、自定义 ruleCategories、静态导入

定义测试方法

JUnit 使用注解将方法标记为测试方法并配置它们。下表概述了 JUnit4.x5.x 版本中最重要的注释。所有这些注释都可以用于方法。

Table 1. 注解
注解 描述

@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如果比较失败,它会抛出一个。

Table 2. 断言
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));

Similar Posts

上一篇 Testng源码阅读

Comments

Table of contents