一、什么是单元测试?为什么要用单元测试?
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。之所以要做单元测试,是因为几乎没有人能够保证自己写出的代码没有bug,单元测试就是用来对代码进行验证来避免一些bug。单元测试是由开发人员在开发的过程中同步进行,看起来比较麻烦,实际上这是发现并解决bug成本最低的方式。
二、junit相关的概念
现在普遍都是以junit4为主了,所以我们也就不考虑之前的版本。
1、junit4中常用的注解
@BeforeClass:在该测试类中所有测试方法之前执行该方法,该方法需要是静态方法,一般是用于获取资源。一个测试类中可以有多个@BeforeClass修饰的静态方法。
@Before:在所有的测试方法执行之前都会执行该方法。一个测试类中可以有多个@Before修饰的方法。
@Test:表明一个方法为测试方法。该方法名字可以随便取(一般为testXXX),没有任何限制,但是返回值必须为 void ,而且不能有任何参数。
@Ignore:执行测试方法的时候会忽略该方法
@After:没个测试方法执行之后就会执行该方法。一个测试类中可以有多个@After修饰的方法。
@AfterClass:该测试类所有测试方法执行之后就会执行该方法,同样该方法应该是静态方法,一般用于释放资源。一个测试类中可以有多个@AfterClass修饰的静态方法。
这些方法的执行顺序为@BeforeClass –> @Before –> @Test –> @After –> @AfterClass
@RunWith:指定测试类使用某个运行器
@Parameters:指定测试类的测试数据集合
@Rule:允许灵活添加或重新定义测试类中的每个测试方法的行为
@FixMethodOrder:指定测试方法的执行顺序
2、断言
一般在对测试结果进行判定的时候我们不是通过手动去判定该方法测试是否通过,然后将结果打印出来,或者抛出异常。对测试结果进行判定时都是通过断言来进行判断。
常用的断言如下:
assertArrayEquals(expecteds, actuals) | 查看两个数组是否相等。 |
assertEquals(expected, actual) | 查看两个对象是否相等。类似于字符串比较使用的equals()方法 |
assertNotEquals(first, second) | 查看两个对象是否不相等。 |
assertNull(object) | 查看对象是否为空。 |
assertNotNull(object) | 查看对象是否不为空。 |
assertSame(expected, actual) | 查看两个对象的引用是否相等。类似于使用“==”比较两个对象 |
assertNotSame(unexpected, actual) | 查看两个对象的引用是否不相等。类似于使用“!=”比较两个对象 |
assertTrue(condition) | 查看运行结果是否为true。 |
assertFalse(condition) | 查看运行结果是否为false。 |
assertThat(actual, matcher) | 查看实际值是否满足指定的条件 |
fail() | 让测试失败 |
三、使用junit来进行测试
1、引入jar包
2、业务代码
public class Calculator { public int add(int a, int b){ return a + b; } public int minus(int a, int b){ return a - b; } public static int divide(int a, int b){ return a/b; } }
public class NormalClass { public int doOperation(int a, int b){ return a + b; } }
3.测试代码
public class CalculatorTest { /*@Rule public Timeout timeout = new Timeout(1000);*/ @Before public void before(){ System.out.println("before"); } @BeforeClass public static void beforeClass(){ System.out.println("beforeClass"); } @Test public void testAdd() { int result = new Calculator().add(1, 2); //assertEquals(3,result); assertThat(result, is(3)); } @Test public void testMinus() { int result = new Calculator().minus(12345, 12341); assertEquals(4,result); } @Test(expected=ArithmeticException.class)//预计会抛出什么异常 public void testDivide() { int result = new Calculator().divide(123,0); assertEquals(41,result); } @Test(timeout = 1000)//单位毫秒 public void testTimeout() throws InterruptedException{ Thread.sleep(800); } @Ignore public void testMultiply(){ int result = new Calculator().multiply(12,3); assertEquals(36,result); } @After public void after(){ System.out.println("after"); } @AfterClass public static void afterClass(){ System.out.println("afterClass"); } }
//参数化测试,可以模拟多种输入和输出测试而不需要写多个测试方法 @RunWith(Parameterized.class) public class NormalClassTest { private int num1; private int num2; private int result; public NormalClassTest(int num1,int num2,int result){ this.num1 = num1; this.num2 = num2; this.result = result; } @Parameters public static Collection<Object[]> prepareAddData(){ Object[][] data = new Object[][]{ {128,128,256},{1,2,3},{4,5,9} }; return Arrays.asList(data); } @Test public void testDoOperation() { NormalClass nc = new NormalClass(); int actualResult = nc.doOperation(num1, num2); assertEquals(result, actualResult); } }
4、测试套件
一个项目会有很多类,对应的也会有很多测试类,如果一个个去手动执行很累。junit可以将一些测试类按照业务模块组合在一起,一起执行。
@RunWith(Suite.class) @SuiteClasses({ CalculatorTest.class, NormalClassTest.class }) public class SuiteTest { }