JUnit4(二)高级之运行器

一、概述

当一个类被@RunWith注释或拓展了一个@RunWith注释的类,JUnit将会使用引用的类来执行测试,而不是使用JUnit内置的运行器。

  • JUnit4的默认运行器(runner)是 BlockJUnit4ClassRunner ,其取代了原来的JUnit4ClassRunner运行器。
  • Annotating a class with @RunWith(JUnit4.class) will always invoke the default JUnit 4 runner in the current version of JUnit, this class aliases the current default JUnit 4 class runner.
  • @RunWith(JUnit4.class)注释类总是会在当前版本的JUnit中调用默认的JUnit 4运行器,这个类是当前默认的JUnit 4类运行器的别名。

Specialized[专业的] Runners

  • Suite:Suite【测试集】是一个标准的运行器允许你手动构件包含来自许多类的测试集。
  • Parameterized:Parameterized【参数化】是一个标准的运行器来实现参数化测试。运行参数化测试类时,测试方法和测试数据进行合并来创建测试实例。
  • Categories:你可以使用Categories运行器来制定一组测试被包含或排除。

Third Party Runners:

  • SpringJUnit4ClassRunner
  • MockitoJUnitRunner
  • HierarchicalContextRunner
  • Avh4’s Nested
  • NitorCreation’s NestedRunner

二、使用Suite进行打包测试

使用Suite运行器允许你手动创建一个包含多个类的测试集。使用@RunWith(Suite.class)@SuiteClasses(TestClass1.class, ...)来注释类。然后你可以运行这个类,其会运行 @SuiteClasses 中指定的所有类。

@RunWith 注解指定使用 org.junit.runners.Suite 运行器进行运行测试类。@Suite.SuiteClasses 告诉测试运行器 Suite 该测试包含哪些测试类。

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

@RunWith(Suite.class)
@Suite.SuiteClasses({
  TestFeatureLogin.class,
  TestFeatureLogout.class,
  TestFeatureNavigate.class,
  TestFeatureUpdate.class
})

public class FeatureTestSuite {
  // the class remains empty,
  // used only as a holder for the above annotations
}

注意:我们可以直接使用 @SuiteClasses 注解来取代 @Suite.SuiteClasses 注解。

三、使用Parameterized进行参数化测试

定制的Parameterized运行器实现了参数化测试。在运行参数化测试类时,将测试方法和测试数据进行合并进而创建实例。

例如,我们来测试一个Fibonacci【斐波纳契】函数,如下:

public class Fibonacci {
    public static int compute(int n) {
        int result = 0;
        if (n <= 1) {
            result = n;
        } else {
            result = compute(n - 1) + compute(n - 2);
        }
        return result;
    }
}
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 FibonacciTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {     
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }  
           });
    }

    private int fInput;
    private int fExpected;

    public FibonacciTest(int input, int expected) {
        fInput= input;
        fExpected= expected;
    }

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

每一个FibonacciTest实例使用两个参数进行构造,而数据值来自@Parameters指定的方法。

使用@Parameter进行字段注入来取代构造器

也可以使用@Parameter注解将数据值直接注入到字段中,而不需要构造函数,示例如下:

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.Parameter;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }  
           });
    }

    @Parameter // first data value (0) is default
    public /* NOT private */ int fInput;

    @Parameter(1)
    public /* NOT private */ int fExpected;

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

public class Fibonacci {
    ...
}

单参数测试(Since 4.12-beta-3)

如果你的测试只需要一个参数,则不需要用数组包装它。相反,您可以提供一个Iterable或数组对象。

@Parameters
public static Iterable<? extends Object> data() {
    return Arrays.asList("first test", "second test");
}

@Parameters
public static Object[] data() {
    return new Object[] { "first test", "second test" };
}

识别单个测试用例

为了方便地识别参数化测试中的单个测试用例,您可以使用@Parameters注解并提供一个名称。此名称允许包含在运行时替换的占位符:

  • {index}: 当前参数索引
  • {0}, {1}, …: the first, second, and so on, parameter value. NOTE: 单引号 ' 应该转义为两个单引号''

示例:

import static org.junit.Assert.assertEquals;
import java.util.Arrays;
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 FibonacciTest {

    @Parameters(name = "{index}: fib({0})={1}")
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] {
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
           });
    }

    private int input;
    private int expected;

    public FibonacciTest(int input, int expected) {
        this.input = input;
        this.expected = expected;
    }

    @Test
    public void test() {
        assertEquals(expected, Fibonacci.compute(input));
    }
}

public class Fibonacci {
    ...
}

在上面给出的示例中,参数化运行程序创建的名称类似于[1: fib(3)=2]。如果不指定名称,默认情况下将使用当前参数索引。

四、使用Categories进行分类测试

从给定的一组测试类中,Categories 运行器只运行@IncludeClass注解中指定的类别的类和方法。类或接口都可以用作类别【categories】,因此也具有继承关系。如果@IncludeClass指定了@Category({SubClass.class}),那么其所包含的@Category({SubClass.class})子类别也将会运行。

还可以通过使用@ExcludeCategory 注解来排除类别,示例:

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
}

Maven中使用categories

你可以通过[maven-surefire-plugin][surefire] (用于单元测试) 或 [maven-failsafe-plugin][failsafe] (用于集成测试)插件来使用类别【Categories】。使用任何一个插件,你可以配置一个包含或排除的类别【Categories】列表。在不使用任何一种选项的情况下,所有测试都将在默认情况下执行。

<build>
  <plugins>
    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
        <groups>com.example.FastTests,com.example.RegressionTests</groups>
      </configuration>
    </plugin>
  </plugins>
</build>

类似地,要排除某个类别,您可以使用<excludedGroups/>配置元素。

Gradle中使用categories

Gradle的测试任务允许指定要包含和排除的JUnit类别。

test {
    useJUnit {
        includeCategories 'org.gradle.junit.CategoryA'
        excludeCategories 'org.gradle.junit.CategoryB'
    }
}

类别的典型用法

Categories are used to add metadata on the tests.

The frequently encountered categories usages are about:

  • The type of automated tests: UnitTests, IntegrationTests, SmokeTests, RegressionTests, PerformanceTests …?
  • How quick the tests execute: SlowTests, QuickTests * In which part of the ci build the tests should be executed: NightlyBuildTests
  • The state of the test: UnstableTests, InProgressTests

This is also used to add project specific metadata like which feature of a project is covered by the test.

See usages of Junit Categories on github hosted projects

参考资料:

赞赏码

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值