Junit4精简解析

来源:互联网 发布:绯夜传奇 知乎 编辑:程序博客网 时间:2024/06/05 05:16

JUnit4是JUnit框架有史以来的最大改进,其主要目标便是利用Java5的Annotation特性简化测试用例的编写。先简单解释一下什么是Annotation,这个单词一般是翻译成元数据。元数据是什么?元数据就是描述数据的数据。也就是说,这个东西在Java里面可以用来和public、static等关键字一样来修饰类名、方法名、变量名。修饰的作用描述这个数据是做什么用的,差不多和public描述这个数据是公有的一样。想具体了解可以看Core Java2。
废话不多说了,直接进入正题。

比如你在一个叫AddOperation的类中定义一个计算加法的方法

public class AddOperation {      public int add(int x,int y){          return x+y;      }}

那么我们要测试这个加的方法就可以在同一包下新建一个Junit Test Case文件,里面的重载方法默认就行了。

import junit.framework.TestCase;import org.junit.After;import org.junit.Before;import org.junit.Test;import static org.junit.Assert.*;/**** @author bean*/public class AddOperationTest extends TestCase{      public AddOperationTest() {      }     @BeforeClass    public static void setUpBeforeClass() throws Exception {    }    @AfterClass    public static void tearDownAfterClass() throws Exception {    }    @Before    public void setUp() throws Exception {    }    @After    public void tearDown() throws Exception {    }      @Test      public void add() {         System.out.println("add");          int x = 0;          int y = 0;          AddOperation instance = newAddOperation();          int expResult = 0;          int result = instance.add(x,y);          assertEquals(expResult,result);      }}

从上面的例子可以看到在JUnit 4中还引入了一些其他的元数据,下面一一介绍:

@BeforeClass
在测试类开始运行时调用这个Annotaion里的方法

@AfterClass
在整个测试类结束时调用这个Annotation里的方法

@Before:
使用了该元数据的方法在每个测试方法执行之前都要执行一次。
某些方法在每次执行前需要一些初始化工作的话,使用@Before做准备工作,然后再测试。

@After:
使用了该元数据的方法在每个测试方法执行之后要执行一次。
进行一些资源释放和内存清理。

注意:@Before和@After标示的方法只能各有一个。这个相当于取代了JUnit以前版本中的setUp和tearDown方法,当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。

@Test(expected=*.class)
在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)来测试。现在,通过@Test元数据中的expected属性。expected属性的值是一个异常的类型

@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,
如果测试方法在制定的时间之内没有运行完,则测试也失败。

@ignore:
该元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库联接,而在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。

@Test(expected = ArithmeticException.class)
异常测试,比如指定可能的一场为算术异常。

@Test(expected = ArithmeticException.class)  public void divideByZero() ...{    calculator.divide(0);   }

介绍完简单的测试之后,再来说下复杂一点的参数测试。

参数化测试。

你可能遇到过这样的函数,它的参数有许多特殊值,或者说他的参数分为很多个区域。比如,一个对考试分数进行评价的函数,返回值分别为“优秀,良好,一般,及格,不及格”,因此你在编写测试的时候,至少要写5个测试,把这5中情况都包含了,这确实是一件很麻烦的事情。我们还使用我们先前的例子,测试一下“计算一个数的平方”这个函数,暂且分三类:正数、0、负数。测试代码如下:

import org.junit.AfterClass;import org.junit.Before;import org.junit.BeforeClass;import org.junit.Test;import static org.junit.Assert.*; public class AdvancedTest ...{ private static Calculator calculator = new Calculator();    @Beforepublic void clearCalculator() ...{        calculator.clear();}    @Testpublic 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提出了“参数化测试”的概念,只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。代码如下:

import static org.junit.Assert.assertEquals;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import org.junit.runners.Parameterized.Parameters; import java.util.Arrays;import java.util.Collection; @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());    } }

下面我们对上述代码进行分析。首先,你要为这种测试专门生成一个新的类,而不能与其他测试共用同一个类,此例中我们定义了一个SquareTest类。然后,你要为这个类指定一个Runner,而不能使用默认的Runner了,因为特殊的功能要用特殊的Runner嘛。@RunWith(Parameterized.class)这条语句就是为这个类指定了一个ParameterizedRunner。第二步,定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。接下来,定义测试数据的集合,也就是上述的data()方法,该方法可以任意命名,但是必须使用@Parameters标注进行修饰。这个方法的框架就不予解释了,大家只需要注意其中的数据,是一个二维数组,数据两两一组,每组中的这两个数据,一个是参数,一个是你预期的结果。比如我们的第一组{2, 4},2就是参数,4就是预期的结果。这两个数据的顺序无所谓,谁前谁后都可以。之后是构造函数,其功能就是对先前定义的两个参数进行初始化。在这里你可要注意一下参数的顺序了,要和上面的数据集合的顺序保持一致。如果前面的顺序是{参数,期待的结果},那么你构造函数的顺序也要是“构造函数(参数, 期待的结果)”,反之亦然。最后就是写一个简单的测试例了,和前面介绍过的写法完全一样,在此就不多说。

最后上两个完整的代码片(talk is cheap show me the code)

参数测试

Math类

package perMute;import TreeSet.intCompare;public class Math {public Math(){}public int add(int i,int j) {    return i+j;}}

MathTest类(参数化测试)

package perMute;import java.util.Arrays;import java.util.Collection;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import org.junit.runners.Parameterized.Parameters;/** * 参数化测试的类必须有Parameterized测试运行器修饰 *  */@RunWith(Parameterized.class)public class mMathTest {    Math math = new Math();    private int input1;    private int input2;    private int expected;    /**     * 准备数据。数据的准备需要在一个方法中进行,该方法需要满足一定的要求:     *      * 1)该方法必须由Parameters注解修饰 2)该方法必须为public static的 3)该方法必须返回Collection类型     * 4)该方法的名字不做要求 5)该方法没有参数     *      * @return     */    @Parameters    @SuppressWarnings("unchecked")    public static Collection prepareData() {        Object[][] object = { { -1, -2, -3 }, { 0, 2, 2 }, { -1, 1, 0 },                { 1, 2, 3 } };        return Arrays.asList(object);    }    public mMathTest(int input1, int input2, int expected) {        this.input1 = input1;        this.input2 = input2;        this.expected = expected;    }    @Test    public void testAdd() {        Assert.assertEquals(expected, math.add(input1, input2));    }}

快速排序和全排列单元测试

待测试类(三个方法需要被测试)

package perMute;import java.awt.List;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashSet;import java.util.Iterator;import java.util.Set;public class perMute {    public String[] allSort1(String str) {        int len = str.length();        if (len == 0) {            return null;        }        int count = 0, n = 1;        for (int i = 1; i <= len; i++) {            n *= i;        }        String[] strings = new String[n];        String mtuxString = str;        if (len == 1) {            strings[0] = mtuxString;        }        // while (!str.equals(mtuxString)) {        // mtuxString = swap(mtuxString, n, --n);        // }        for (int i = 0; i < n / len; i++) {            if (i % 2 == 0) {                for (int j = len - 1; j > 0; j--) {                    mtuxString = swap(mtuxString, j, j - 1);                    strings[count++] = mtuxString;                    if (j == 1) {                        mtuxString = swap(mtuxString, len - 1, len - 2);                        strings[count++] = mtuxString;                    }                }            } else {                for (int j = 1; j <= len - 1; j++) {                    mtuxString = swap(mtuxString, j, j - 1);                    strings[count++] = mtuxString;                    if (j == len - 1) {                        mtuxString = swap(mtuxString, 0, 1);                        strings[count++] = mtuxString;                    }                }            }        }        return strings;    }    public static ArrayList<String> allSort2(String str, int pos) {        ArrayList<String> list = new ArrayList<String>();        if(pos==0){//          str=quickSort(str);        }        int len = str.length();        if (len == 0) {            list.add("");            return list;        }        list.add(str);        if (len == 1) {            return list;        }        for (int i = pos; i < len; i++) {            str = swap(str, i, pos);            list.add(str);            if (pos < len - 1) {                list.addAll(allSort2(str, pos + 1));            } else {                return list;            }        }        return list;    }    public static String swap(String str, int i, int j) {        if (str.length() == 0) {            return null;        }        String afterSwap = "";        char c;        char[] cs = str.toCharArray();        c = cs[i];        cs[i] = cs[j];        cs[j] = c;        afterSwap = String.valueOf(cs);        return afterSwap;    }    /**     * Qucik sort 54,12,9,89,3,19,29,1 (1)选择54作为中轴 并定义tmp=54 1,12,9,89,3,19,29,1     * (2) 定义一个队尾游标,从后向前扫描,选择小于54的第一个元素,并把它复制到54这个位置 1,12,9,89,3,19,29,89     * (3)定义一个队首游标,从前向后扫描,扫描到大于54的第一个元素,并把它复制到1这个位置 1,12,9,29,3,19,29,89     * (4)继续步骤2的扫描,扫描小于54的第一个元素,并把它复制到89这个位置 1,12,9,29,3,19,54,89     * (5)继续步骤3的扫描,当扫描游标触碰到队尾游标时还未发现大于54的元素,则把tmp复制到队尾游标所指向的位置     * (1,12,9,29,3,19)54(89) (6)分别对54左右两个数组执行步骤1     *      * @param str     * @return     */    public static String quickSort(String str) {        int len = str.length();        if (len == 0) {            return "";        }        if (len == 1) {            return str;        }        String resultStr = "";        char[] cr = str.toCharArray();        char pivol = cr[0];        int i = 0, j = len - 1;        while (true) {            if (i < j) {                while (j >= 0 && j > i) {                    if (cr[j] > pivol) {                        j--;                    } else {                        cr[i] = cr[j];                        break;                    }                }                while (i < len && j > i) {                    if (cr[i] <= pivol) {                        i++;                    } else {                        cr[j] = cr[i];                        break;                    }                }            } else {                cr[j] = pivol;                resultStr = String.valueOf(cr);                break;            }        }        return quickSort(resultStr.substring(0, j)) + pivol                + quickSort(resultStr.substring(j + 1, len));    }    public static void cout1() {        System.out.println("class before");    }    public static void cout2() {        System.out.println("method before");    }    public static void cout3() {        System.out.println("class after");    }    public static void cout4() {        System.out.println("method after");    }

测试类

package perMute;import static org.junit.Assert.*;import org.junit.After;import org.junit.AfterClass;import org.junit.Before;import org.junit.BeforeClass;import org.junit.Ignore;import org.junit.Test;public class perMuteTest {    perMute pm = new perMute();    @BeforeClass    public static void testBeforeClass() {        // TODO Auto-generated method stub        perMute.cout1();    }    @Before    public  void testbefore() {        // TODO Auto-generated method stub        perMute.cout2();    }    @AfterClass    public static void testAfterClass(){        perMute.cout3();    }    @After    public void testAfter(){        perMute.cout4();    }    @Test    public void testAllSort1() {        assertNull(pm.allSort1(""));        String[] strings1 = { "a" };        assertArrayEquals(strings1, pm.allSort1("a"));        String[] strings2 = { "ba", "ab" };        assertArrayEquals(strings2, pm.allSort1("ab"));        String[] strings3 = { "acb", "cab", "cba", "bca", "bac", "abc" };        assertArrayEquals(strings3, pm.allSort1("abc"));        String[] strings4 = { "abdc", "adbc", "dabc", "dacb", "adcb", "acdb",                "acbd", "cabd", "cadb", "cdab", "dcab", "dcba", "cdba", "cbda",                "cbad", "bcad", "bcda", "bdca", "dbca", "dbac", "bdac", "badc",                "bacd", "abcd" };        assertArrayEquals(strings4, pm.allSort1("abcd"));    };    @Ignore("UnImplemented do not test")    @Test    public void testAllSort2() {        fail("Not yet implemented");    }    @Test(timeout=10)    public void testSwap() {        assertNull("null", pm.swap("", 0, 0));        assertNull("null", pm.swap("", 0, 2));        assertEquals(pm.swap("a", 0, 0), "a");        assertEquals(pm.swap("a", 0, 0), "a");        assertEquals(pm.swap("abc", 1, 2), "acb");        assertEquals(pm.swap("abcd", 2, 3), "abdc");        assertEquals(pm.swap("abcd", 0, 1), "bacd");    }    @Test(timeout=50)    public void testquickSort(){        assertEquals("", pm.quickSort(""));        assertEquals("a", pm.quickSort("a"));        assertEquals("1", pm.quickSort("1"));        assertEquals("22", pm.quickSort("22"));        assertEquals("123", pm.quickSort("123"));        assertEquals("123", pm.quickSort("321"));        assertEquals("123", pm.quickSort("213"));        assertEquals("123", pm.quickSort("312"));        assertEquals("1223", pm.quickSort("3212"));        assertEquals("123456", pm.quickSort("123456"));        assertEquals("123456", pm.quickSort("653214"));        assertEquals("abc", pm.quickSort("abc"));        assertEquals("abc", pm.quickSort("bca"));        assertEquals("abc", pm.quickSort("cab"));        assertEquals("cccc", pm.quickSort("cccc"));        assertEquals("acuyz", pm.quickSort("acuyz"));        assertEquals("acuyz", pm.quickSort("uyzca"));        assertEquals("acuyz", pm.quickSort("czyua"));    }}
0 0
原创粉丝点击