单元测试是编写测试代码,应该准确、快速地保证程序基本模块的正确性。
好的单元测试的标准
JUnit是Java单元测试框架,已经在Eclipse中默认安装。html
JUnit4经过注解的方式来识别测试方法。目前支持的主要注解有:框架
基本测试eclipse
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; } }
public class CalculatorTest { private static Calculator calculator = new Calculator(); @Before public void setUp() throws Exception { calculator.clear(); } @Test public void testAdd() { calculator.add(3); calculator.add(4); assertEquals(7, calculator.getResult()); } @Test public void testSubstract() { calculator.add(8); calculator.substract(3); assertEquals(5, calculator.getResult()); } @Ignore("Multiply() Not yet implemented") @Test public void testMultiply() { fail("Not yet implemented"); } @Test public void testDivide() { calculator.add(8); calculator.divide(2); assertEquals(4, calculator.getResult()); } }
@Test(timeout = 1000) public void squareRoot() { calculator.squareRoot(4); assertEquals(2, calculator.getResult()); }
Timeout参数代表了你要设定的时间,单位为毫秒,所以1000就表明1秒。ide
JAVA中的异常处理也是一个重点,所以你常常会编写一些须要抛出异常的函数。那么,若是你以为一个函数应该抛出异常,可是它没抛出,这算不算Bug呢?这固然是Bug,并JUnit也考虑到了这一点,来帮助咱们找到这种Bug。例如,咱们写的计算器类有除法功能,若是除数是一个0,那么必然要抛出“除0异常”。所以,咱们颇有必要对这些进行测试。代码以下:函数
@Test(expected = ArithmeticException.class) public void divideByZero(){ calculator.divide(0); }
如上述代码所示,咱们须要使用@Test标注的expected属性,将咱们要检验的异常传递给他,这样JUnit框架就能自动帮咱们检测是否抛出了咱们指定的异常。
参数化测试
咱们可能遇到过这样的函数,它的参数有许多特殊值,或者说他的参数分为不少个区域。
例如,测试一下“计算一个数的平方”这个函数,暂且分三类:正数、0、负数。在编写测试的时候,至少要写3个测试,把这3种状况都包含了,这确实是一件很麻烦的事情。测试代码以下:单元测试
public class AdvancedTest { private static Calculator calculator = new Calculator(); @Before public void clearCalculator(){ calculator.clear(); } @Test public void square1() { calculator.square(2); assertEquals(4, calculator.getResult()); } @Test public void square2(){ calculator.square(0); assertEquals(0, calculator.getResult()); } @Test public void square3(){ calculator.square(-3); assertEquals(9, calculator.getResult()); } }
为了简化相似的测试,JUnit4提出了“参数化测试”的概念,只写一个测试函数,把这若干种状况做为参数传递进去,一次性的完成测试。代码以下:测试
@RunWith(Parameterized.class) public class SquareTest{ private static Calculator calculator = new Calculator(); private int param; private int result; @Parameters public static Collection data() { return Arrays.asList(new Object[][]{ {2, 4}, {0, 0}, {-3, 9}, }); } //构造函数,对变量进行初始化 public SquareTest(int param, int result){ this.param = param; this.result = result; } @Test public void square(){ calculator.square(param); assertEquals(result, calculator.getResult()); } }
执行了3次该测试类,依次采用了数据集合中的数据{处理值,预期处理结果},结果以下:
代码分析以下:ui