单元测试:如何在jUnit4中应用两个@RunWith?

2021/8/11 单元测试Java

比如正在使用 spring boot starter test 来编写 JUnit 测试用例。但很想使用 JunitParamrunner,它有助于为参数化测试传递文件。

基本上它从文件中逐行读取数据,并为每一行调用一个测试用例。

问题是同时使用需要通过@RunWith 和 SpringJUnit4ClassRunner 以及 JUnitParamsRunner。

那需要在junit中@RunWith(SpringJUnit4ClassRunner.class)和@RunWith(Parameterized. class)这个要怎么写呢?

# 解决方案

其实对于@RunWith(SpringJUnit4ClassRunner.class),无非就是让测试运行于Spring的测试环境。

而我们可以在测试类的构造函数中初始化上下文TestContextManager就相当于集成了spring测试环境,也相当于代替了@RunWith(SpringJUnit4ClassRunner.class)注解。

  1. 书写一个测试基类
/**
 * 测试基类,所有测试类都要继承此类
 */
@ContextConfiguration(locations="classpath: application-context.xml")
// @RunWith(SpringJUnit4ClassRunner.class)
// @SpringBootTest
// @RunWith(SpringRunner.class)
// @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
// @ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {XxlJobConfig.class})})
public class BaseTest {

    // 排除一个bean,Spring将使用这个mock而不是真正的类,所以不会调用@PostConstruct方法去创建
    @MockBean
    private XxlJobSpringExecutor xxlJobSpringExecutor;

    private TestContextManager testContextManager;

    public ParametrizedTestWithSpring() throws Exception {
        this.testContextManager = new TestContextManager(getClass());
        this.testContextManager.prepareTestInstance(this);
    }

    @BeforeClass
    public static void setUp() throws Exception {
        URL url = BaseTest.class.getClassLoader().getResource("");
        String path = url.getPath() = "../../../docker/config/";
        System.setProperty("env.cfg", path);
        System.setProperty("spring.profiles.active", "dev");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  1. 编写测试类,添加第二个@RunWith(Parameterized. class)
@RunWith(Parameterized.class )
public class Demo1ControllerTest extends BaseTest {
    
    private static final Logger logger = LoggerFactory.getLogger(Demo1ControllerTest.class);
    // 测试参数
    private String target;
    // 预期返回结果
    private String except;
    @Autowired
    private Demo1Controlle demo1Controller;

    /**
     * 测试案例集
     */
    @Parameters
    public static Collection setParam() {
       return Arrays.asList(new Object[][] { 
           { "emplee_info", "empleeInfo" }, // 测试正常情况
           { null, null }, // 测试null时处理情况
           { "", "" }, // 测试空字符串的情况
           { "employee_info", "EmployeeInfo" }, // 测试当首字母大写时的情况
           { "employee_info_a", "employeeInfoA" }, // 测试当尾字母为大写时的情况
           { "employee_a_info", "employeeAInfo" } // 测试多个相连字母大写时的情况
       });
    }

    /**
     * 参数化测试必须的构造函数
     *
     * @param except 期望的测试结果 ,对应参数集中的第一个参数
     * @param target 测试数据,对应结果集中的第二个参数
     */
    public TestDemoParamter(String target, String except) {
       this.except = except;
       this.target = target;
    }

    @Test(timeout = 1000)
    public void testParam(){
        logger.info("入参:{}", target);
        String except = demo1Controller.testParam();
        logger.info("反参:{}", except);
        Assert.assertEquals(except, target);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 知识扩展

# @RunWith作用

@RunWith 就是一个运行器:

  • @RunWith(JUnit4.class) 就是指用JUnit4来运行

  • @RunWith(SpringJUnit4ClassRunner.class), 让测试运行于Spring测试环境

    此时需要搭配@ContextConfiguration 使用,Spring整合JUnit4测试时,使用注解引入多个配置文件

  • @RunWith(Suite.class) 的话就是一套测试集合

@ContextConfiguration语法:

  • 单个文件

    @ContextConfiguration(locations=“classpath:applicationContext.xml”)

    @ContextConfiguration(classes = SimpleConfiguration.class)

  • 多个文件时,可用{}

    @ContextConfiguration(locations = { “classpath:spring1.xml”, “classpath:spring2.xml” })

# 使用@RunWith 和@Parameters 进行参数化测试

# 什么是参数化

  • 怎么测试多分支?

    如一个对考试分数进行评价的函数

    返回值分别为“优秀,良好,一般,及格,不及格”

    在编写测试的时候,如果编写 5 个测试方法,进而测试 5 种情况,是 一件很麻烦的事情。

  • 为了简化类似的测试,JUnit 提出了“参数化测试”的概念,只写一个测试函 数,把这若干种情况作为参数传递进去,一次性的完成测试。

# @Parameters:用于JUnit的参数化功能,用来标记准备数据的方法。

注意:该方法需要满足一定的要求:

  1. 该方法必须为public static的

  2. 该方法返回值必须为java.util.Collection类型

  3. 该方法的名字不做要求

  4. 该方法没有参数

  5. 参数化测试必须有与之对应的构造函数

具体demo实类如上的Demo1ControllerTest

此生不换
青鸟飞鱼