Junit
1. 概念
JUnit是一个Java语言的单元测试框架。
单元测试:单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
2. Junit特性
-
测试工具
- 测试套件
- 测试运行器
- 测试分类
3. API
注解
序号 | 注释 | 描述 |
---|---|---|
1 | @Test | 依附在Junit的public void方法上,作为一个测试用例。 |
2 | @Before | 表示必须在每一个测试之前执行,以便执行测试某些必要的先决条件。 |
3 | @BeforeClass | 依附在静态方法上,在类的所有测之前必须执行。一般是测试计算共享配置方法(连接到数据库)。 |
4 | @After | 表示在每一个测试后执行,如执行每一个测试后重置或删除某些变量。 |
5 | @AfterClass | 在所有测试用例后执行,可用于清理建立方法,如断开数据库连接。和@BeforeClass一样附着的方法必须是静态。 |
6 | @Ignore | 当想暂时禁用特定的测试执行的时候可以使用,被注解为@Ignore的方法将不被执行。 |
-
代码示例:
import org.junit.*; /** * Created by Administrator on 2017/11/1 0001. */ public class TestAnnotation { //指出这是附着在静态方法必须执行一次并在类的所有测试之前。 // 发生这种情况时一般是测试计算共享配置方法(如连接到数据库) @BeforeClass public static void beforeClass(){ System.out.println("execute beforeClass"); } //当需要执行所有的测试在JUnit测试用例类后执行,AfterClass注解可以使用以清理建立方法, // (从数据库如断开连接)。注意:附有此批注(类似于BeforeClass)的方法必须定义为静态。 @AfterClass public static void afterClass(){ System.out.println("execute afterClass"); } //Before注释表示,该方法必须在类中的每个测试之前执行,以便执行测试某些必要的先决条件。 @Before public void before(){ System.out.println("execute before"); } //After 注释指示,该方法在执行每项测试后执行(如执行每一个测试后重置某些变量,删除临时变量等) @After public void after(){ System.out.println("execute after"); } //测试注释指示该公共无效方法它所附着可以作为一个测试用例。 @Test public void test(){ System.out.println("execute test"); } @Test public void test1(){ System.out.println("execute test1"); } //当想暂时禁用特定的测试执行可以使用忽略注释。每个被注解为@Ignore的方法将不被执行。 @Ignore public void ignoreTest(){ System.out.println(); } }
import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; /** * Created by Administrator on 2017/11/1 0001. */ public class TestRunner2 { public static void main(String[] args) { Result result= JUnitCore.runClasses(TestAnnotation.class); for (Failure failure:result.getFailures()){ System.out.println(failure.toString()); } System.out.println(result.wasSuccessful()); } }
-
运行结果:
execute beforeClass execute before execute test execute after execute before execute test1 execute after execute afterClass true
-
junit的执行过程
- beforeClass首先执行,只执行一次
- afterClass最后执行,只执行一次
- before在每次测试之前执行
- after在每次测试之后执行
- 每个test在after和before之间执行
断言
序号 | 方法 | 描述 |
---|---|---|
1 | assertEquals(boolean expected, boolean actual) | 检查两个变量或者等式是否平衡 |
2 | assertTrue(boolean expected, boolean actual) | 检查条件是否为真 |
3 | assertFalse(boolean condition) | 检查条件是否为假 |
4 | assertNotNull(Object object) | 检查变量是否不为空 |
5 | assertNull(Object object) | 检查变量是否为空 |
6 | assertSame(Object expected, Object actual) | 检查两个引用是否指向同一个对象 |
7 | assertNotSame(Object expected, Object actual) | 检查两个引用是否不指向同一个对象 |
8 | assertArrayEquals(expectedArray, resultArray) | 检查两个数组是否相等 |
-
代码示例
import org.junit.Test; import static org.junit.Assert.*; public class TestAssertions { @Test public void testAssertions(){ String str1=new String("abc"); String str2=new String("abc"); String str3=null; String str4="abc"; String str5="abc"; int val1=5; int val2=6; String[] expectedArray={"one","two","three"}; String[] resultArray={"one","two","three"}; assertEquals(str1,str2); assertTrue(val1<val2); assertFalse(val1>val2); assertNotNull(str1); assertNull(str3); assertSame(str4,str5); assertNotSame(str1,str3); assertArrayEquals(expectedArray,resultArray); } }
4. 执行测试
测试用例通过JUnitCore类来执行,它是Junit运行测试的外观类。对于只有一次的测试运行,可以使用静态方法:runClasses(Class[])
5. 套件测试
意思就是捆绑几个单元测试用例并一起执行。@RunWith和@Suite可一起用于运行套件测试
-
代码示例
/** * Created by Administrator on 2017/11/1 0001. * 被测试类 */ public class MessageUtil { private String message; public MessageUtil(String message){ this.message=message; } public String printMessage(){ System.out.println(message); return message; } public String salutationMessage(){ message="Hi!"+message; System.out.println(message); return message; } }
import org.junit.Assert; import org.junit.Test; /** * Created by Administrator on 2017/11/1 0001. */ public class TestJunit { String message="Robert"; MessageUtil messageUtil=new MessageUtil(message); @Test public void testPrintMessage(){ // message="New Word"; System.out.println("Inside testPrintMessage()"); Assert.assertEquals(message,messageUtil.printMessage()); } }
import org.junit.Assert; import org.junit.Test; /** * Created by Administrator on 2017/11/1 0001. */ public class TestJunit1 { String message = "Robert"; MessageUtil messageUtil=new MessageUtil(message); @Test public void testSalutationMessage(){ System.out.println("Inside testSalutationMessage()"); message="Hi!"+"Robert"; Assert.assertEquals(message,messageUtil.salutationMessage()); } }
测试执行类:
```
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
/**
* Created by Administrator on 2017/11/1 0001.
*/
public class TestRunner2 {
public static void main(String[] args) {
Result result= JUnitCore.runClasses(JunitTestSuite.class);
for (Failure failure:result.getFailures()){
System.out.println(failure.toString());
}
System.out.println(result.wasSuccessful());
}
}
```
- 运行结果
Inside testPrintMessage() Robert Inside testSalutationMessage() Hi!Robert true
6. 忽略测试
- 一个含有@Ignore 注释的测试方法不会被执行
- 如果一个测试类有@Ignore注释,则它的测试方法将不会被执行
7. 时间测试
-
timeout参数与@Test注释一起使用,当一个测试用例比指定毫秒数花费更多时间,那么Junit将会自动将它标记为失败。
-
代码示例:
/** * Created by Administrator on 2017/11/1 0001. */ public class MessageUtil { private String message; public MessageUtil(String message){ this.message=message; } public void printMessage(){ System.out.println(message); while (true); } public String salutationMessage(){ message="Hi!"+message; System.out.println(message); return message; } }
import org.junit.Assert; import org.junit.Test; /** * Created by Administrator on 2017/11/1 0001. */ public class TestJunit4 { String message = "Robert"; MessageUtil messageUtil=new MessageUtil(message); @Test(timeout = 1000) public void testPrintMessage(){ System.out.println("Inside testPrintMessage"); messageUtil.printMessage(); } @Test public void testSalutationMessage(){ System.out.println("Inside testSalutationMessage"); message="Hi!"+"Robert"; Assert.assertEquals(message,messageUtil.salutationMessage()); } }
import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; /** * Created by Administrator on 2017/11/1 0001. */ public class TestRunner2 { public static void main(String[] args) { Result result= JUnitCore.runClasses(TestJunit4.class); for (Failure failure:result.getFailures()){ System.out.println(failure.toString()); } System.out.println(result.wasSuccessful()); } }
-
运行结果
Inside testSalutationMessage Hi!Robert Inside testPrintMessage Robert testPrintMessage(TestJunit4): test timed out after 1000 milliseconds false
8. 异常测试
-
expected参数与@Test注释一起使用,可以测试代码是否抛出你想要得到的异常。
-
代码示例
/** * Created by Administrator on 2017/11/1 0001. */ public class MessageUtil { private String message; public MessageUtil(String message){ this.message=message; } public void printMessage(){ System.out.println(message); // return message; // while (true); int a=0; int b=1/a; } public String salutationMessage(){ message="Hi!"+message; System.out.println(message); return message; } }
import org.junit.Assert; import org.junit.Test; /** * Created by Administrator on 2017/11/1 0001. */ public class TestJunit5 { String message = "Robert"; MessageUtil messageUtil=new MessageUtil(message); @Test(expected = ArithmeticException.class) public void testPrintMessage(){ System.out.println("Inside testPrintMessage"); messageUtil.printMessage(); } @Test public void testSalutationMessage(){ System.out.println("Inside testSalutationMessage"); message="Hi!"+"Robert"; Assert.assertEquals(message,messageUtil.salutationMessage()); } }
-
运行结果
Inside testSalutationMessage Hi!Robert Inside testPrintMessage Robert true
9. 参数化测试
-
参数化测试允许开发人员使用不同的值反复运行同一个测试用例。
- 用@RunWith(Parameterized.class)来注释test类
- 创建一个由@Parameterized.Parameters注释的公共静态方法,返回一个对象的集合(数组)来作为测试数据集合。
- 创建一个公共构造函数,用来接收和存储测试数据。
- 用例会反复运行,为每一组测试数据创建一个实例变量
- 用实例变量作为测试数据的来源来创建你的测试用例
-
代码示例
判断是不是素数:public class PrimeNumberChecker { public Boolean validate(final Integer primeNumber){ for (int i = 2; i < (primeNumber / 2); i++) { if (primeNumber%i==0){ return false; } } return true; } }
import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.Collection; /** * Created by Administrator on 2017/11/1 0001. */ @RunWith(Parameterized.class) public class PrimeNumberCheckerTest { private Integer inputNumber; private Boolean expectedResult; private PrimeNumberChecker primeNumberChecker; @Before public void initialize(){ System.out.println("initialize"); primeNumberChecker=new PrimeNumberChecker(); } public PrimeNumberCheckerTest(Integer inputNumber,Boolean expectedResult){ System.out.println("construct"); this.inputNumber=inputNumber; this.expectedResult=expectedResult; } @Parameterized.Parameters public static Collection primeNumbers(){ return Arrays.asList(new Object[][]{ {2,true}, {6,true}, {19,true}, {22,true}, {23,true} }); } @Test public void testPrimeNumberChecker(){ System.out.println("test"); System.out.println("Parameterized Number is : " + inputNumber); Assert.assertEquals(expectedResult, primeNumberChecker.validate(inputNumber)); } }
import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; /** * Created by Administrator on 2017/11/1 0001. */ public class TestRunner2 { public static void main(String[] args) { Result result= JUnitCore.runClasses(PrimeNumberCheckerTest.class); for (Failure failure:result.getFailures()){ System.out.println(failure.toString()); } System.out.println(result.wasSuccessful()); } }
-
运行结果
construct initialize test Parameterized Number is : 2 construct initialize test Parameterized Number is : 6 construct initialize test Parameterized Number is : 19 construct initialize test Parameterized Number is : 22 construct initialize test Parameterized Number is : 23 testPrimeNumberChecker[1](PrimeNumberCheckerTest): expected:<true> but was:<false> testPrimeNumberChecker[3](PrimeNumberCheckerTest): expected:<true> but was:<false> false