如何做好UnitTest(二):junit4的高级用法@RunWith

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

@Runwith注解是Junit4中的一个高级用法。首先看看该注解的注释描述:

When a class is annotated with @RunWith or extends a class annotated with @RunWith, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit. We added this feature late in development. While it seems powerful we expect the runner API to change as we learn how people really use it. Some of the classes that are currently internal will likely be refined and become public. For example, suites in JUnit 4 are built using RunWith, and a custom runner named Suite:
   @RunWith(Suite.class)
   @SuiteClasses({ATest.class, BTest.class, CTest.class})
   public class ABCSuite {
   }
   
Since:
4.0
复制代码

意思是说,当一个类用@RunWith注释或继承一个用@RunWhith注释的类时,JUnit将调用它引用的运行器来运行该类中的测试用例,而不是JUnit默认的运行器。默认的Junit运行器是BlockJUnit4ClassRunner,这个运行器是在4.4之后引入的,在此之前是一个JUnit4ClassRunner的类。

这说明,所有的测试用例的执行离不开这个Runner,默认的情况下,不加RunWith标签,就会使用默认的Runner执行,如果要使用其他的Runner,则在RunWith中进行标注。

具体能支持哪像Runner呢?直接查看Runner借口的实现类即可:

image.png

@RunWith(Suite.class)

Suit本身也是一个Runner,其源码如下:

image.png

Suit的目的就是将多个待测试的类,打包(Suite)一起测试。需要放在一起测试的类放在@SuiteClasses注解中。执行Suit,就可以同时运行配置的所有测试结果。 Suit的类:

@RunWith(Suite.class)
@SuiteClasses({JunitDemo.class, JunitDemo1.class})
public class RunwithDemo {

}
复制代码

测试类 JunitDemo:

public class JunitDemo {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("***********This is beforeClass! ");
    }

    @Before
    public void before() {
        System.out.println("############This is before!");
    }
    @Test
    public void testCase() {
        System.out.println("This is test case!");
    }

    @Test
    public void testCase1() {
        System.out.println("This is test case1!");
    }

    @Ignore
    public void ignoreCase() {
        System.out.println("This is ignore case!");
    }

    @After
    public void after() {
        System.out.println("##########This is after!");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("***********This is afterClass!");
    }
}
复制代码

测试类JunitDemo1:

public class JunitDemo1 {

    @Test
    public void testCase() {
        System.out.println("This is JunitDemo1 test case!");
    }
}
复制代码

上述用例执行结果:

image.png

需要注意的是,@RunWith(Suite.class)的类必须为空,否则会出现如下错误:

java.lang.Exception: No tests found matching Method testCase(com.dhb.test.RunwithDemo) from org.junit.internal.requests.ClassRequest@4f2410ac
	at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:50)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)


Process finished with exit code -1

复制代码

@RunWith(Categories.class)

还有一个与Suit相关的Runner是Categories,这个Runner的作用可以将现有的测试用例分类,然后分别在不同的Suit下执行。因为上面关于Suit的例子中,组合Suit的粒度是测试的class,取决于SuiteClasses中的情况。但是如果我们想要区分得更细,以单个case来分组,那么就可以用Categories。具体用法如下:

先定义两个用于测试case分组的空接口:

public interface TestA {

}

public interface TestB {

}
复制代码

这两个接口分别标识测试用例的类别,不需要定义任何方法。

测试用例类case1:

public class Case1 {

    @Category(TestA.class)
    @Test
    public void a() {
        System.out.println("Case1 a test");
    }


    @Category(TestB.class)
    @Test
    public void b() {
        System.out.println("Case1 b test");
    }
}
复制代码

case2:

public class Case2 {

    @Category(TestA.class)
    @Test
    public void a() {
        System.out.println("Case2 a test");
    }


    @Category(TestB.class)
    @Test
    public void b() {
        System.out.println("Case2 b test");
    }
}
复制代码

测试suit的两个类suitA:

@RunWith(Categories.class)
@IncludeCategory(TestA.class)
@ExcludeCategory(TestB.class)
@SuiteClasses( { Case1.class, Case2.class })
public class CategoriesSuitA {

}
复制代码

执行结果:

image.png

suitB:

@RunWith(Categories.class)
@IncludeCategory(TestB.class)
@ExcludeCategory(TestA.class)
@SuiteClasses( { Case1.class, Case2.class })
public class CategoriesSuitB {

}
复制代码

执行结果:

image.png 这样就可以进一步以测试方法为目标将测试用例分组。组合成需要的suit进行执行。

总结

不难理解,Suit实际上就是相关测试的case的组合。 关于@Runwith 可以运行的Runner还有很多,将在后面的文章继续介绍。

猜你喜欢

转载自juejin.im/post/7132078725339840519
今日推荐