Junit4入门
简介:
JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。
JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。
入门实例:
先创建一个测试类Calculator
public class Calculator {
private static int result; // 静态变量,用于存储运行结果
public void add(int n) {
result = result + n;
}
public void substract(int n) {
result = result - 1; //Bug: 正确的应该是 result =result-n
}
public void multiply(int n) {
} // 此方法尚未写好
public void divide(int n) {
result = result / n;
}
public void square(int n) {
result = n * n;
}
public void squareRoot(int n) {
for (; ;) ; //Bug : 死循环
}
public void clear() { // 将结果清零
result = 0;
}
public int getResult() {
return result;
}
}
然后在Calculator类右键new里面选择JUnit Test Case
生成CalculatorTest类
public class CalculatorTest {
private static Calculator calculator = new Calculator();
@Before
public void setUp() throws Exception {
calculator.clear();//复原操作,不被其他结果影响
}
@Test
public void testAdd() {
calculator.add(5);
calculator.add(1);
assertEquals(6, calculator.getResult());//将预计结果与实际结果进行对比
}
@Test
public void testSubstract() {
calculator.add(10);
assertEquals(9, calculator.getResult());
}
@Test
public void testMultiply() {
fail("Not yet implemented");
}
@Test
public void testDivide() {
calculator.add(8);
calculator.divide(2);
assertEquals(4, calculator.getResult());
}
}
Junit的运行流程
可以定义一个类TestFlow
public class TestFlow {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("BeforeClass...");
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("AfterClass...");
}
@Before
public void setUp() throws Exception {
System.out.println("Before...");
}
@After
public void tearDown() throws Exception {
System.out.println("After...");
}
@Test
public void test1() {
System.out.println("test1");
}
@Test
public void test2() {
System.out.println("test2");
}
}
输出:
BeforeClass...
Before...
test2
After...
Before...
test1
After...
AfterClass...
可以看出,beforeclass和afterclass在整个运行流程就在开头和结尾执行,但是before和after会在每个测试方法执行前后执行
Junit基本注解
@BeforeClass注解
被@BeforeClass注解的方法会是: 只被执行一次 运行junit测试类时第一个被执行的方法 这样的方法被用作执行计算代价很大的任务,如打开数据库连接。被@BeforeClass 注解的方法应该是静态的(即 static类型的).
@AfterClass注解
被@AfterClass注解的方法应是: 只被执行一次 运行junit测试类是最后一个被执行的方法 该类型的方法被用作执行类似关闭数据库连接的任务。被@AfterClass 注解的方法应该是静态的(即 static类型的).
@Before注解
被@Before 注解的方法应是: junit测试类中的任意一个测试方法执行 前 都会执行此方法 该类型的方法可以被用来为测试方法初始化所需的资源。
@After注解
被@After注解的方法应是: junit测试类中的任意一个测试方法执行后 都会执行此方法, 即使被@Test 或 @Before修饰的测试方法抛出异常 该类型的方法被用来关闭由@Before注解修饰的测试方法打开的资源。
@Test 注解
被@Test注解的测试方法包含了真正的测试代码,并且会被Junit应用为要测试的方法。@Test注解有两个可选的参数: expected 表示此测试方法执行后应该抛出的异常,(值是异常名) timeout 检测测试方法的执行时间
JUnit测试套件使用及参数化设置
JUnit测试套件 如果在测试类不端增加的情况下,如何运行所有的单元测试代码类?一个个测试类的执行吗?显然繁琐且费劲。 将要运行的测试类集成在我们的测试套件中,比如一个系统功能对应一个测试套件,一个测试套件中包含多个测试类,每次测试系统功能时,只要执行一次测试套件就可以了。
如下三个测试类要一起测试
public class Task01Test {
@Test
public void test() {
System.out.println("Task01Test.test()");
}
}
public class Task02Test {
@Test
public void test() {
System.out.println("Task02Test.test()");
}
}
public class Task03Test {
@Test
public void test() {
System.out.println("Task03Test.test()");
}
}
可以新建一个套件类,包含以上三个任务类:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({Task01Test.class,Task02Test.class,Task03Test.class})
public class SuiteTest {
/*
* 1.测试套件就是组织测试类一起运行的
*
* 写一个作为测试套件的入口类,这个类里不包含其他的方法
* 更改测试运行器Suite.class
* 将要测试的类作为数组传入到Suite.SuiteClasses({})
*/
}
①使用@RunWith注解,修改测试运行器。例如@RunWith(Suite.class),这个类就成为测试套件的入口类。
②@Suite.SuiteClasses()中放入测试套件的测试类,以数组的形式{class1,class2,......}作为参数
JUnit参数化设置
如果测试代码大同小异,代码结构都是相同的,不同的只是测试的数据和预期值,那么有没有更好的办法将相同的代码结构提取出来,提高代码的重用度呢? 解决:进行参数化测试。 步骤:
①要进行参数化测试,需要在类上面指定如下的运行器:@RunWith (Parameterized.class)
②然后,在提供数据的方法上加上一个@Parameters注解,这个方法必须是静态static的,并且返回一个集合Collection。
③在测试类的构造方法中为各个参数赋值,(构造方法是由JUnit调用的),最后编写测试类,它会根据参数的组数来运行测试多次。
import static org.junit.Assert.*;
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 ParameterTest {
int expected =0;
int input1 = 0;
int input2 = 0;
//3.声明一个返回值 为Collection的公共静态方法,并使用@Parameters进行修饰
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{3,1,2},
{4,2,2}
}) ;
}
//4.为测试类声明一个带有参数的公共构造函数,并在其中为之声明变量赋值
public ParameterTest(int expected,int input1,int input2) {
this.expected = expected;
this.input1 = input1;
this.input2 = input2;
}
@Test
public void testadd(){
assertEquals(expected, new Calcul().add(input1, input2));
}
}