zoukankan      html  css  js  c++  java
  • JUnit单元测试教程(翻译自Java Code Geeks)

    说明

    本教程翻译自Java Code Geeks,原文网址:https://www.javacodegeeks.com/2014/11/junit-tutorial-unit-testing.html#suite_tests。翻译的过程中,有少部分内容是译者添加的解释说明和对原文章中错误地方的修正。水平有限,如果有错误的地方,希望能在我的博客里告诉我,谢谢。 
    相关的例子不想自己写的同学们可以去这里下载:http://download.csdn.net/detail/rainnnbow/9603847

    1. 单元测试简介

    1.1 什么是单元测试?

    一个单元可以是一个方法、一个类、一个包、 或者一个子系统。所以术语单元测试表示对代码中的很小的单元的测试行为,以确保它们能够按预期工作。例如,我们给定一些输入,测试是否是预期的输出,或者测试一个条件是真还是假。 
    这种测试行为能帮助开发者发现隐藏在代码后面的错误,并提高代码质量。单元测试也被用来确保代码能够按照预期工作,以防止未来可能的变化。

    1.2 测试覆盖

    总的来说,开发者社区对代码测试要达到多少比例存在不同的观点。许多开发者认为代码的测试覆盖率要达到100%。另一些则认为50%或者更低就可以了。但无论如何,你都应该为你的代码中复杂的以及重要的部分编写测试。

    1.3 Java中的单元测试

    Java中最著名的测试框架是JUnit,本指南是专门介绍JUnit的,接下来的部分将详细介绍该测试框架的更多细节。Java中另一个著名的测试框架是TestNG。

    2. JUnit简介

    JUnit是一个开源的测试框架,它被用来编写和运行可重复的自动化测试,保证我们的代码按照预期的执行。JUnit被广泛使用:它可以在Java程序中单独使用(使用命令行)或者结合IDE使用,如Eclipse。 
    JUnit提供以下功能:

    • 断言测试的预期结果。
    • 共享测试数据的特性。
    • 使用Test suites简化测试用例的组织和运行。
    • 图形化和文本化测试用例?(Graphical and textual test runners.)

    JUnit可以用来测试以下内容:

    • 一个对象
    • 部分对象——一个方法或几个相互影响的方法
    • 多个对象之间的交互

    2.1 使用Eclipse实现简单JUnit测试例子

    在这一节我们将展示一个简单的JUnit例子。首先来看一下我们要测试的类: 
    Calculate.java:

    package com.javacodegeeks.junit;
    
    public class Calculate {
    
        public int sum(int var1, int var2) {
            System.out.println("Adding values: " + var1 + " + " + var2);
            return var1 + var2;
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在上面的源码中,我们看到该类有一个public的方法sum(),方法接受两个int参数,相加之后返回结果。我们将测试这个方法。因此我们需要创建另一个类,并在这个类中为测试Calculate类中的所有需要测试的方法一一编写测试方法(在这个例子中,我们只有一个方法需要测试)。这是最普通的使用方法。当然如果一个方法非常复杂,我们可以为这个方法编写多个测试方法。编写测试用例的更多细节,我们将在下一节介绍。下面的CalculateTest.java类就是我们的测试类:

    package com.javacodegeeks.junit;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class CalculateTest {
    
        Calculate calculation = new Calculate();
        int sum = calculation.sum(2, 5);
        int testSum = 7;
    
        @Test
        public void testSum() {
            System.out.println("@Test sum(): " + sum + " = " + testSum);
            assertEquals(sum, testSum);
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    让我们来解释一下上面的代码。首先我们看到在testSum()方法上有一个@Test注解。这个注解表示这个方法可以作为一个测试用例运行。所以testSum()方法被用来测试sum()方法。我们还看到了assertEquals(sum, testSum)方法,assertEquals ([String message], object expected, object actual)方法用来接手两个对象,并断言这两个对象是否相等。 
    运行该测试类,Run As–>JUnit Test,程序输出将如下所示:

    这里写图片描述

    为了查看JUnit测试的实际结果,Eclipse提供了JUnit窗口来显示测试结果。在这个用例中,测试成功,JUnit窗口不会显示任何错误或失败信息,所以我们看到了如下所示的界面:

    这里写图片描述

    如果我们改变一下代码:

    int testSum = 10;
    • 1

    修改代码后两个整数的测试不再相等,程序输出将如下所示:

    这里写图片描述

    同时,在JUnit窗口中会显示测试出错,并给出错误信息:

    这里写图片描述

    2.2 JUnit注解 
    本节我们将介绍JUnit4支持的基本注解,下表是对这些索引的总结:

    这里写图片描述

    让我们来看一个包含了以上注解的测试类的例子: 
    AnnotationsTest.java:

    package com.javacodegeeks.junit;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertTrue;
    
    import java.util.ArrayList;
    
    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 AnnotationsTest {
    
        private ArrayList testList;
    
        /**
         * if the method isn't static, throw following exception:
         * java.lang.Exception: Method onceExecutedBeforeAll() should be static
         */
        @BeforeClass
        public static void onceExecutedBeforeAll() {
            System.out.println("@BeforeClass: onceExecutedBeforeAll");
        }
    
        @Before
        public void executedBeforeEach() {
            testList = new ArrayList();
            System.out.println("@Before: executedBeforeEach");
        }
    
        /**
         * If the method isn't static, throw following exception:
         * java.lang.Exception: Method onceExecutedAfterAll() should be static
         */
        @AfterClass
        public static void onceExecutedAfterAll() {
            System.out.println("@AfterClass: onceExecutedAfterAll");
        }
    
        @After
        public void executedAfterEach() {
            testList.clear();
            System.out.println("@After: executedAfterEach");
        }
    
        @Test
        public void EmptyCollection() {
            assertTrue(testList.isEmpty());
            System.out.println("@Test: EmptyArrayList");
        }
    
        @Test
        public void OneItemCollection() {
            testList.add("oneItem");
            assertEquals(1, testList.size());
            System.out.println("@Test: OneItemArrayList");
        }
    
        @Ignore
        public void executionIgnored() {
            System.out.println("@Ignore: This execution is ignored");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    执行以上测试,控制台输出如下所示:

    这里写图片描述

    JUnit窗口显示如下信息:

    这里写图片描述

    2.3 Junit断言 
    本节我们将展示一些断言方法。所有这些方法由Assert类提供,Assert类继承自java.lang.Object。这些断言能帮助你编写测试用例,监测到失败的测试。下表是对一些最常用的断言方法的详细介绍:

    这里写图片描述

    让我们看一个上述断言的例子: 
    AssertionsTest.java

    package com.javacodegeeks.junit;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class AssertionsTest {
    
        @Test
        public void test() {
    
            String obj1 = "junit";
            String obj2 = "junit";
            String obj3 = "test";
            String obj4 = "test";
            String obj5 = null;
            int var1 = 1;
            int var2 = 2;
            int[] arithmetic1 = {1,2,3};
            int[] arithmetic2 = {1,2,3};
    
            assertEquals(obj1, obj2);
            assertSame(obj3, obj4);
            assertNotSame(obj2, obj4);
            assertNotNull(obj1);
            assertNull(obj5);
            assertTrue(var1 != var2);
            assertFalse(var1 == var2);
            assertArrayEquals(arithmetic1, arithmetic2);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    从以上类中我们可以看到断言方法是怎样工作的。

    • assertEquals():如果两个对象相等,方法正常返回;否则在JUnit窗口中将显示错误,该测试将被中断。
    • assertSame()与assertNotSame():测试两个对象的引用是否指向了同一个对象。
    • assertNull()与assertNotNull():测试一个变量是否是null或非null。
    • assertTrue()与assertFalse():测试一个条件或变量时true或false.。
    • assertArrayEquals():比较两个数组是否相等。如果相等,方法正常返回;否则在JUnit窗口中将显示错误,该测试将被中断。

    3. 使用Eclipse实现完整的JUnit例子

    本节我们将展示一个使用JUnit的完整例子。我们将讲解怎样创建和运行测试用例,以及怎样使用JUnit的注解和断言。

    3.1 创建工程

    创建一个名为JUnitGuide的java工程。创建一个包com.javacodegeeks.junit用来放被测试的类。对于测试类,一个好的实践是创建一个专用于测试的源码包。这样被测试类和测试类就被分在了不同的源码包中。创建test包:右键单击你的工程, New–>Source Folder,命名源码包为test。 
    这里写图片描述 
    提示:创建源码包的另一种方式:右键单击你的工程PropertiesJava Build Path,选择Source 项,然后Add FolderCreate New Folder。输入源码包名,点击finish。 
    你能看到在工程里有两个源码包: 
    这里写图片描述 
    你可以在test源码包中也创建一个名称为com.javacodegeeks.junit的包,这样你的测试类就不会被放在默认的包中。

    3.2 创建要被测试的Java类

    右击src源码包,创建一个名为FirstDayAtScholl.java的类。该类的public方法将被测试。 
    FirstDayAtSchool.java 
    这里写图片描述

    3.3 创建并运行JUnit测试用例

    为已经存在的类FirstDayAtSchool.java创建测试用例:选中FirstDayAtSchool.java类,右击选择NewJUnit Test Case。改变源码包,将测试用例类放在test源码包中。确保选择“JUnit 4 test”选项。 
    这里写图片描述

    点击“Finish”。如果你的项目classpath下还没有包含JUnit4,将会弹出如下所示的信息让你将JUnit4 Library添加进你的工程中。 
    这里写图片描述 
    (译者注:也可以直接在test源码包中像创建普通类一样创建一个测试用例类。只要该类中的方法用@Test注解标注上,就能引入JUnit框架,并成为测试用例。)

    以下就是我们创建的名为FirstDayAtSchoolTest.java的测试用例。 
    FirstDayAtSchoolTest.java 
    这里写图片描述

    右键Run AsJUnit Test,运行测试用例。 
    程序输出如下所示: 
    这里写图片描述 
    JUnit窗口显示如下: 
    这里写图片描述 
    此时JUnit窗口没有任何错误或失败。如果我们改变其中一个数组,让它包含比预期更多的元素: 
    这里写图片描述 
    再次运行测试类,JUnit窗口将显示有一个失败的测试用例: 
    这里写图片描述 
    或者,我们再次改变数组,让它包含与预期不同的元素: 
    这里写图片描述 
    再次运行测试类,JUnit窗口将再次显示一个测试用例fail: 
    这里写图片描述

    3.4 使用@Ignore注解

    在上面的例子中,让我们看看怎样使用@Ignore注解。在测试类FirstDayAtSchoolTest.java的testAddPencils()方法上标注@Ignore注解。通过这种方式,我们将该测试方法忽略掉,测试时不会执行。 
    这里写图片描述 
    执行测试,输出如下所示:@Ignore注解的测试方法没有执行。 
    这里写图片描述 
    JUnit窗口显示如下: 
    这里写图片描述

    现在,我们去掉testAddPencils()方法上的@Ignore注解,将@Ignore注解标注在FirstDayAtSchoolTest.java类上。 
    这里写图片描述 
    运行该测试类发现:整个测试用例将不会执行,所以控制台上没有任何输出。JUnit窗口显示如下信息: 
    这里写图片描述

    3.5 创建测试套件(suite tests)

    本节,我们将展示如何创建测试套件。测试套件是来自于不同类的多个测试用例的集合。使用@Runwith和@Suite注解可以让这些测试类一起运行。当你有许多测试类并且你希望这些测试类一起执行时,这是非常有用的。 
    在上一节类的基础上,我们可以创建两个测试类。一个测试prepareMyBag()方法,另一个测试addPencils()方法。两个测试类如下所示:

    PrepareMyBagTest.java. 
    这里写图片描述

    AddPencilsTest.java. 
    这里写图片描述

    我们来创建一个测试套件类来运行以上两个测试类。测试套件类SuiteTest.java如下所示: 
    SuiteTest.java. 
    这里写图片描述 
    使用@Suite.SuiteClasses注解来定义哪些测试类将被包含进测试套件一起执行。 
    运行该测试套件,这两个测试类将按照在@Suite.SuiteClasses注解中声明的顺序执行。 
    执行完毕后JUnit窗口显示信息如下: 
    这里写图片描述

    3.6 创建参数化测试(parameterized tests)

    本节我们将展示如何创建参数化的测试。我们将使用前面的2.1节中的类作为被测试类。 
    什么时候一个测试类才能被认为是一个参数化的测试类呢?当测试类满足下列条件的时候:

     该类使用@RunWith(Parameterized.class)标注; 
    @RunWith注解告诉JUnit使用该注解标明的执行器执行测试用例,而不是使用JUnit内置的默认执行器。Parameterized是JUnit中的一个执行器,该执行器将使用一组不同的输入来多次执行一个相同的测试用例。 
     该类有唯一的构造函数来创建测试数据; 
     该类有一个static方法用来产生并返回测试数据,该方法使用@Parameters注解标注; 
     该类有一个使用@Test标注的测试用例(译者注:废话吗这不是)。 
    我们创建了一个新的测试类CalculateTest.java。该类遵循以上的规则。该类源码如下: 
    这里写图片描述

    上如代码满足以上的所有规则。addedNumbers方法使用@Parameters标注,返回数组的集合。每一个数组包含一次测试执行的I/O数据。数组中元素的个数必须和构造函数中参数的个数一致。在该例子中,一个数组包含三个元素,两个代表要被相加的数,一个代表结果。

    运行该测试用例,控制台输出如下所示: 
    这里写图片描述 
    JUnit窗口输出信息如下: 
    这里写图片描述

    从上述信息可以看出,该测试用例执行了4次,这正是使用@Parameters注解标注的方法中输入的测试数据的个数。

    3.7 规则(Rules)

    本节我们将介绍JUnit4的一个新特性,叫做规则(Rules)。Rules允许我们灵活的增加或重新定义每一个测试方法的行为。为达到这个目的,使用@Rule注解标注测试类中public的域(fields)。这些域必须是MethodRule类型的,他们标明了一个测试方法的运行或结果报告作出了哪些改变。一个测试方法可以应用多个MethodRule。MethodRule接口有许多实现,如ErrorCollector,该规则允许测试用例在发现第一次错误是可以继续运行;ExpectedException,该规则允许我们明确预期异常的类型及异常信息;TestName,该规则允许我们在测试方法中获取到当前测试方法的名称;等等其他规则。除了JUnit已经定义的规则,开发者也可以自定义规则并在测试用例中使用。

    下面,我们展示一个使用已经存在的TestName规则的例子。当一个测试类开始执行时TestName被调用。 
    NameRuleTest.java 
    这里写图片描述

    如上所示:@Rule注解标注了一个public的域name,该域是MethodRule类型的。确切的说,该类是MethodRule接口的实现类MethodRule类型。然后我们就可以使用name在我们的测试方法中获取当前正在运行的测试方法的名字了。

    (译者注:关于Rules的详细说明,请查看JUnit4官方文档:https://github.com/junit-team/junit4/wiki/Rules。运行里面的例子,有疑问就修改例子测试,一目了然。Rules还是有不少用处的。)

    3.8 策略(Categories)

    JUnit的另一个新特性是策略,这允许你将特定的测试放在一起形成一个分组(group),并可以包含或排除某些分组。例如你可以将运行慢的测试用例与运行快的测试用例分开。JUnit提供了@Category注解为一个测试用例标明策略。以下是使用该新特性的例子。该特性从JUnit4.8开始支持。 
    这里写图片描述 
    首先,定义两个策略,FastTests和SlowTests。一个策略可以是一个类或者一个借口。

    这里写图片描述 
    以上的代码中,我们在A类的b()方法上使用了@Category注解,标注该方法在SlowTests策略中。所以,@Category注解不仅可以标注整个类,也可以标注某一个测试方法。 
    这里写图片描述

    以上的代码中,我们看到整个B类使用了@Category标注。在类上标注后,该类的所有测试方法都会自动包含进@Category中声明的策略中。我们也可以看到,一个类或者一个测试方法可以属于多个策略。 
    这里写图片描述

    以上代码中,我们看到有一个名为SlowTestSuite_1的测试套件。一般情况下,我们认为策略就是一种测试套件。在该套件中,我们使用@IncludeCategory注解标明哪些策略将会被执行。在该例中,属于SlowTests策略的所有方法将会被执行。因此,A类中的b()方法和B类中的c方法将被执行,他们都属于SlowTests策略。

    这里写图片描述 
    以上代码中,我们对测试套件做了一些修改,我们添加了一个新的注解@ExcludeCategory,该注解表明那些策略将被排除。在本例中,只有A类的b()方法会执行,因为他是唯一只属于SlowTests策略,并不属于FastTests策略的测试方法。

    通过以上两个例子我们看到,A类的a()方法从未执行,因为它不属于任何策略。

    5. 命令行运行JUnit测试

    通过使用org.junit.runner.JUnitCore 类,可以在Eclipse之外运行测试用例。该类提供了runClasses()方法允许执行一个或多个测试类。runClasses()方法的返回类型是一个org.junit.runner.Result对象。该对象可以搜集所有测试的信息。如果有失败的测试用例,你可以使用org.junit.runner.notification.Failure对象来获取失败的测试用例的描述。 
    下面的流程展示了如何在Eclipse之外运行你的测试。 
    创建一个新类JunitRunner.java如下所示: 
    JunitRunner.java 
    这里写图片描述 
    我们选择运行名为AssertionsTest的测试类。 
     打开DOS窗口,并定位到JunitRunner.java所在的目录(译者注:本人的目录是**JUnitGuide estcomjavacodegeeksjunit)。 
     编译测试类和Runner类。 
    javac -classpath “D:learnTech estjunit-4.11.jar”;”D:learnTech esthamcrest-core-1.3.0.jar”; AssertionsTest.java JunitRunner.java 
    这里写图片描述
    和在Eclipse中一样,我们需要将JUnit的jar包包含进classpath中。运行完上述命令。在Junitrunner.java所在的目录下就生成了AssertionsTest.class 和JunitRunner.class两个class文件。如下所示: 
    这里写图片描述 
     在DOS窗口中,退回到test源码目录(译者注:本人的目录是**JUnitGuide est)。 
     运行JunitRunner类。 
    java -classpath “D:learnTech estjunit-4.11.jar”;”D:learnTech esthamcrest-core-1.3.0.jar”; JunitRunner 
    这里写图片描述
    输出结果为: 
    这里写图片描述

    from: https://blog.csdn.net/Rainnnbow/article/details/52217058

  • 相关阅读:
    十一、docker仓库
    十、Docker容器:磁盘&内存&CPU资源限制实战
    八、docker的跨主机网络通信--flanneld
    九、dockerfile制作docker 镜像
    七、自己定制一个docker镜像
    六、docker的数据卷
    五、docker容器的网络访问
    四、docker容器的操作
    三、docker的镜像操作
    商品SKU
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10197953.html
Copyright © 2011-2022 走看看