Junit常用注解
0x01 摘要
本文简要说下junit里面常用注解的含义和使用,还会总结一些常用的Assert判断语句。
0x02 常用Junit注解
2.1 @Test
用在方法上,定义该方法是测试方法。
注意:测试方法必须是public void
,但可以抛异常,不过一般不这么做。
例子:
@Test (timeout = 30000)
public void testRMAppSubmitInvalidResourceRequest() throws Exception {
asContext.setResource(Resources.createResource(
YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB + 1));
// submit an app
try {
appMonitor.submitApplication(asContext, "test");
Assert.fail("Application submission should fail because resource" +
" request is invalid.");
} catch (YarnException e) {
// Exception is expected
// TODO Change this to assert the expected exception type - post YARN-142
// sub-task related to specialized exceptions.
Assert.assertTrue("The thrown exception is not" +
" InvalidResourceRequestException",
e.getMessage().contains("Invalid resource request"));
}
}
2.2 @BeforeClass
2.2.1 含义
用来修饰所有@Test
方法之前只会运行一次的方法。
注意:需用public static void
修饰。
2.2.2 用途
当你的测试中多个方法都会用到的一些公共方法可以抽取到用@BeforeClass
修饰的方法汇总,如创建数据库驱动等。
2.2.3 示例
@BeforeClass
public static void loadDriver(){
try {
Class.forName("org.apache.phoenix.queryserver.client.Driver");
} catch (ClassNotFoundException e) {
logger.error("an exception happened while load driver:", e);
}
}
2.3 @AfterClass
2.3.1 含义
@AfterClass
和前面提到的@BeforeClass
类似,但是在所有@Test
方法之后运行一次。
注意:需用public static void
修饰。
2.3.2 用途
一般他被来处理一些资源清理工作,如关闭数据库连接等。
2.3.3 示例
@AfterClass
public static void closeConnections(){
for(Connection conn : connectionList){
try {
conn.close();
} catch (SQLException e) {
logger.error("an exception happened while close connection:", e);
}
}
}
2.4 @Before
2.4.1 含义
@Before
与@BeforeClass
类似,他们最大区别在于@Before
会在每个@Test
方法运行之前都会运行一次。
注意:必须用public void
修饰,不能加static
。
2.4.2 用途
用于每个测试用例都需要的单独的方法,比如获取插入一条记录到数据。
2.4.3 示例
@Before
public void setUp() {
long now = System.currentTimeMillis();
rmContext = mockRMContext(1, now - 10);
ResourceScheduler scheduler = mockResourceScheduler();
Configuration conf = new Configuration();
ApplicationMasterService masterService =
new ApplicationMasterService(rmContext, scheduler);
appMonitor = new TestRMAppManager(rmContext,
new ClientToAMTokenSecretManagerInRM(), scheduler, masterService,
new ApplicationACLsManager(conf), conf);
appId = MockApps.newAppID(1);
RecordFactory recordFactory = RecordFactoryProvider.getRecordFactory(null);
asContext =
recordFactory.newRecordInstance(ApplicationSubmissionContext.class);
asContext.setApplicationId(appId);
asContext.setAMContainerSpec(mockContainerLaunchContext(recordFactory));
asContext.setResource(mockResource());
setupDispatcher(rmContext, conf);
}
2.5 @After
2.5.1 含义
@After
与@AfterClass
类似,他们最大区别在于@After
会在每个@Test
方法运行之后都会运行一次。
注意:必须用public void
修饰,不能加static
。
2.5.2 用途
可以用来清理每个@Test
用@Before
创建的单独资源、恢复测试初始状态等。
2.5.3 示例
@After
public void tearDown() {
setAppEventType(RMAppEventType.KILL);
((Service)rmContext.getDispatcher()).stop();
}
2.6 @Runwith
2.6.1 含义
首先要分清几个概念:测试方法、测试类、测试集、测试运行器:
- 其中测试方法就是用
@Test
注解的一些函数 - 测试类是包含一个或多个测试方法的一个
Test.java
文件 - 测试集是一个
suite
,可能包含多个测试类 - 测试运行器则决定了用什么方式偏好去运行这些测试集/类/方法
而@Runwith就是放在测试类名之前,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器。
常见的运行器有:
- @RunWith(Parameterized.class) 参数化运行器,配合@Parameters使用junit的参数化功能
- @RunWith(Suite.class)
@SuiteClasses({ATest.class,BTest.class,CTest.class})
测试集运行器配合使用测试集功能
- @RunWith(JUnit4.class)
junit4的默认运行器
- @RunWith(JUnit38ClassRunner.class)
用于兼容junit3.8的运行器
- 一些其它运行器具备更多功能。例如@RunWith(SpringJUnit4ClassRunner.class)集成了spring的一些功能
2.7 @Parameters
用于使用参数化功能。
2.8 @Rule和@TestRule
2.8.1 含义
-
@Rule
方法级别,每个测试方法执行时都会执行被@Rule
注解的成员变量的实现自TestRule
的apply
方法,和@Before类似。 -
@ClassRule
类级别,测试类执行时仅会执行一次被@ClassRule
注解的静态变量的方法,和@BeforeClass)类似。
2.8.2 用途
Before
注解只能作用域当前测试类和子类,而实现了TestRule
的类可以被用于多个测试类,可增加代码复用度。
2.8.3 示例
- Timeout
为所有测试方法指定统一超时时间import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; import java.util.concurrent.TimeUnit; public class TimeoutTest { @Rule public Timeout timeout = new Timeout(1000,TimeUnit.MILLISECONDS); // 测试失败,超时 // org.junit.runners.model.TestTimedOutException: test timed out after 1000 milliseconds @Test public void test1() throws Exception { Thread.sleep(2000); } // 测试成功 @Test public void test2() throws Exception { Thread.sleep(500); } // 测试成功 @Test public void test3() throws Exception { Thread.sleep(1000); } }
- TestName
可获取测试方法名字import static org.junit.Assert.*; import org.junit.*; import org.junit.rules.TestName; public class TestNameTest { @Rule public TestName name = new TestName(); @Test public void testA() { System.out.println(name.getMethodName()); assertEquals("testA", name.getMethodName()); } @Test public void testB() { System.out.println(name.getMethodName()); // fail assertEquals("testC", name.getMethodName()); } }
- TemporaryFolder
import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; /** * @Author: chengc * @Date: 2020-03-12 12:57 */ public class TemporaryFolderTest { // 使用系统临时目录,也可在构造方法上加入路径来指定临时目录 @Rule public TemporaryFolder tempFolder = new TemporaryFolder(new File("/Users/chengc/cc/work/projects/javaDemos/src/main/resources")); @Test public void testTempFolderRule() throws IOException { // 在系统的临时目录下创建目录,当测试方法执行完毕自动删除 File directory = tempFolder.newFolder("test"); System.out.println(directory.getAbsoluteFile()); // 在系统的临时目录下创建文件,当测试方法执行完毕自动删除 File file1 = tempFolder.newFile("tmptest.txt"); File file2 = tempFolder.newFile("tmptest2.txt"); System.out.println(file1.getName()); System.out.println(file2.getParentFile()); System.out.println(file2.getAbsoluteFile()); System.out.println(file2.getCanonicalPath()); } }
- 自定义Rule
实现TestRule即可:import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; /** * @Author: chengc * @Date: 2020-03-12 13:19 */ public class AgeRule implements TestRule { private int age; public AgeRule(int age){ this.age = age; } public int getAge() { return age; } @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { //执行一次测试方法 base.evaluate(); } }; } } import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import java.util.Random; /** * @Author: chengc * @Date: 2020-03-12 13:23 */ public class TestAgeRule { @Rule public AgeRule ageRule = new AgeRule(5); @Test public void test1(){ int age = new Random().nextInt(100); if (age > ageRule.getAge()){ Assert.fail("Beyond the age rule!"); } } }