Junit4

junit4官方网站: https://junit.org/junit4/

junit5官方网站:https://junit.org/junit5/ 

W3Cschool:https://www.w3cschool.cn/junit/ 

慕课:https://www.imooc.com/learn/356

依赖包:hamcrest-core.jar (设置规则的框架,可以有效的增强 junit 的测试能力)

eclipse:https://blog.****.net/qq_40794973/article/details/83579049


目录

JUnit - 概述

JUnit - 环境设置

JUnit - API

JUnit - 编写测试

JUnit - 使用断言

JUnit - 执行过程

JUnit - 执行测试

JUnit - 套件测试

JUnit - 忽略测试

JUnit - 时间测试

JUnit - 异常测试

JUnit - 参数化测试


public class Calculate {
	public int add(int a,int b) {
		return a + b;
	}
	public int subtract(int a, int b) {
		return a - b;
	}
	public int multiply(int a,int b) {
		return a * b;
	}
	public int divide(int a ,int b) {
		return a / b;
	}
}
import static org.junit.Assert.assertEquals;
import org.junit.Ignore;
import org.junit.Test;
public class AnotationTest {

    /*
     * @Test:将一个普通的方法修饰成为一个测试方法
     * 		@Test(expected=XX.class)
     * 		@Test(timeout=毫秒 )
     * @BeforeClass:它会在所有的方法运行前被执行,static修饰
     * @AfterClass:它会在所有的方法运行结束后被执行,static修饰
     * @Before:会在每一个测试方法被运行前执行一次
     * @After:会在每一个测试方法运行后被执行一次
     * @Ignore:所修饰的测试方法会被测试运行器忽略
     * @RunWith:可以更改测试运行器 org.junit.runner.Runner
     */

    /**
     * 下面这段代码预期会抛出一个算术异常,我们添加 expected=ArithmeticException.class
     * 将异常捕获了
     */
    @Test(expected=ArithmeticException.class)
    public void testDivide() {
        assertEquals(3, new Calculate().divide(6, 0));//除数为零
    }

    /**
     * timeout 通常用于对方法运行时间的限定
     */
    @Ignore("...") //"..." 中间可以加入一些说明信息,为什么没有执行  单独执行这个,这个方法是是会被执行的,执行所有会被忽略
    @Test(timeout=2000)
    public void testWhile() {
        while(true) {
            System.out.println("run forever...");
        }
    }

    @Test(timeout=3000)
    public void testReadFile(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

JUnit - 概述 (Junit4)

所谓单元测试是测试应用程序的功能是否能够按需要正常运行,并且确保是在开发人员的水平上,单元测试生成图片。单元测试是一个对单一实体(类或方法)的测试。单元测试是每个软件公司提高产品质量、满足客户需求的重要环节。

单元测试可以由两种方式完成

人工测试 自动测试
手动执行测试用例并不借助任何工具的测试被称为人工测试。
- 消耗时间并单调:由于测试用例是由人力资源执行,所以非常缓慢并乏味。
- 人力资源上投资巨大:由于测试用例需要人工执行,所以在人工测试上需要更多的试验员。
- 可信度较低:人工测试可信度较低是可能由于人工错误导致测试运行时不够精确。
- 非程式化:编写复杂并可以获取隐藏的信息的测试的话,这样的程序无法编写。
借助工具支持并且利用自动工具执行用例被称为自动测试。
- 快速自动化运行测试用例时明显比人力资源快。 
- 人力资源投资较少:测试用例由自动工具执行,所以在自动测试中需要较少的试验员。
- 可信度更高:自动化测试每次运行时精确地执行相同的操作。
- 程式化:试验员可以编写复杂的测试来显示隐藏信息。

什么是 JUnit?

JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。

JUnit 促进了“先测试后编码”的理念,强调建立测试数据的一段代码,可以先测试,然后再应用。这个方法就好比“测试一点,编码一点,测试一点,编码一点……”,增加了程序员的产量和程序的稳定性,可以减少程序员的压力和花费在排错上的时间。

特点:

  • JUnit 是一个开放的资源框架,用于编写和运行测试。
  • 提供注释来识别测试方法。
  • 提供断言来测试预期结果。
  • 提供测试运行来运行测试。
  • JUnit 测试允许你编写代码更快,并能提高质量。
  • JUnit 优雅简洁。没那么复杂,花费时间较少。
  • JUnit 测试可以自动运行并且检查自身结果并提供即时反馈。所以也没有必要人工梳理测试结果的报告。
  • JUnit 测试可以被组织为测试套件,包含测试用例,甚至其他的测试套件。
  • JUnit 在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。

什么是一个单元测试用例?

单元测试用例是一部分代码,可以确保另一端代码(方法)按预期工作。为了迅速达到预期的结果,就需要测试框架。JUnit 是 java 编程语言理想的单元测试框架。

一个正式的编写好的单元测试用例的特点是:已知输入和预期输出,即在测试执行前就已知。已知输入需要测试的先决条件,预期输出需要测试后置条件。

每一项需求至少需要两个单元测试用例:一个正检验,一个负检验。如果一个需求有子需求,每一个子需求必须至少有正检验和负检验两个测试用例。


JUnit - 环境设置

gradle: 

// https://mvnrepository.com/artifact/junit/junit
compile group: 'junit', name: 'junit', version: '4.12'

maven: 

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

注:Eclipse 自带了 junit 的。

测试 JUnit 建立

import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {
    @Test
    public void testAdd() {
        String str= "Junit is working fine";
        assertEquals("Junit is working fine",str);
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class TestRunner {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestJunit.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

 运行 TestRunner:

true


JUnit - API

JUnit 中的重要的 API

JUnit 中的最重要的程序包是 junit.framework 它包含了所有的核心类。一些重要的类列示如下:

序号 类的名称 类的功能
1 Assert assert 方法的集合
2 TestCase 一个定义了运行多重测试的固定装置
3 TestResult TestResult 集合了执行测试样例的所有结果
4 TestSuite TestSuite 是测试的集合

 Assert 类

下面介绍的是 org.junit.Assert 类:

public class Assert extends java.lang.Object

这个类提供了一系列的编写测试的有用的声明方法。只有失败的声明方法才会被记录。Assert 类的重要方法列式如下:

序号 方法和描述
1 void assertEquals(boolean expected, boolean actual) 
检查两个变量或者等式是否平衡
2 void assertFalse(boolean condition) 
检查条件是假的
3 void assertNotNull(Object object) 
检查对象不是空的
4 void assertNull(Object object) 
检查对象是空的
5 void assertTrue(boolean condition) 
检查条件为真
6 void fail() 
在没有报告的情况下使测试不通过
import org.junit.Test;
import static org.junit.Assert.*;
public class TestJunit1 {
    @Test
    public void testAdd() {
        //test data
        int num= 5;
        String temp= null;
        String str= "Junit is working fine";

        //check for equality
        assertEquals("Junit is working fine", str);

        //check for false condition
        assertFalse(num > 6);

        //check for not null value
        assertNotNull(str);
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner1 {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestJunit1.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

 输出:

true

 TestCase 类

下面介绍的是 org.junit.TestCaset 类:

public abstract class TestCase extends Assert implements Test

测试样例定义了运行多重测试的固定格式。TestCase 类的一些重要方法列式如下:

序号 方法和描述
1 int countTestCases()
为被run(TestResult result) 执行的测试案例计数
2 TestResult createResult()
创建一个默认的 TestResult 对象
3 String getName()
获取 TestCase 的名称
4 TestResult run()
一个运行这个测试的方便的方法,收集由TestResult 对象产生的结果
5 void run(TestResult result)
在 TestResult 中运行测试案例并收集结果
6 void setName(String name)
设置 TestCase 的名称
7 void setUp()
创建固定装置,例如,打开一个网络连接
8 void tearDown()
拆除固定装置,例如,关闭一个网络连接
9 String toString()
返回测试案例的一个字符串表示
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
public class TestJunit2 extends TestCase  {
    protected double fValue1;
    protected double fValue2;

    @Before
    public void setUp() {
        fValue1= 2.0;
        fValue2= 3.0;
    }

    @Test
    public void testAdd() {
        //count the number of test cases
        System.out.println("No of Test Case = "+ this.countTestCases());

        //test getName
        String name= this.getName();
        System.out.println("Test Case Name = "+ name);

        //test setName
        this.setName("testNewAdd");
        String newName= this.getName();
        System.out.println("Updated Test Case Name = "+ newName);
    }
    //tearDown used to close the connection or clean up activities
    public void tearDown(  ) {
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner2 {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestJunit2.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println("------------------------");
        System.out.println(result.wasSuccessful());
    }
}

 输出:

No of Test Case = 1
Test Case Name = testAdd
Updated Test Case Name = testNewAdd
------------------------
true

 TestResult 类

下面定义的是 org.junit.TestResult 类:

public class TestResult extends Object

TestResult 类收集所有执行测试案例的结果。它是收集参数层面的一个实例。这个实验框架区分失败和错误。失败是可以预料的并且可以通过假设来检查。错误是不可预料的问题就像 ArrayIndexOutOfBoundsException。TestResult 类的一些重要方法列式如下:

序号 方法和描述
1 void addError(Test test, Throwable t)
在错误列表中加入一个错误
2 void addFailure(Test test, AssertionFailedError t)
在失败列表中加入一个失败
3 void endTest(Test test)
显示测试被编译的这个结果
4 int errorCount()
获取被检测出错误的数量
5 Enumeration errors()
返回错误的详细信息
6 int failureCount()
获取被检测出的失败的数量
7 void run(TestCase test) 运行 TestCase
8 int int runCount()
获得运行测试的数量
9 void startTest(Test test)
声明一个测试即将开始
10 void stop()
标明测试必须停止
import org.junit.Test;
import junit.framework.AssertionFailedError;
import junit.framework.TestResult;

public class TestJunit3 extends TestResult {
    // add the error
    public synchronized void addError(Test test, Throwable t) {
        super.addError((junit.framework.Test) test, t);
    }

    // add the failure
    public synchronized void addFailure(Test test, AssertionFailedError t) {
        super.addFailure((junit.framework.Test) test, t);
    }
    @Test
    public void testAdd() {
        // add any test
    }

    // Marks that the test run should stop.
    public synchronized void stop() {
        //stop the test here
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner3 {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestJunit3.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

 输出:

true

 TestSuite 类

下面定义的是 org.junit.TestSuite 类:

public class TestSuite extends Object implements Test

 TestSuite 类是测试的组成部分。它运行了很多的测试案例。TestSuite 类的一些重要方法列式如下:

序号 方法和描述
1 void addTest(Test test) 
在套中加入测试。
2 void addTestSuite(Class<? extends TestCase> testClass)
将已经给定的类中的测试加到套中。
3 int countTestCases()
对这个测试即将运行的测试案例进行计数。
4 String getName()
返回套的名称。
5 void run(TestResult result)
在 TestResult 中运行测试并收集结果。
6 void setName(String name)
设置套的名称。
7 Test testAt(int index)
在给定的目录中返回测试。
8 int testCount()
返回套中测试的数量。
9 static Test warning(String message)
返回会失败的测试并且记录警告信息。
import junit.framework.*;
public class JunitTestSuite {
    public static void main(String[] a) {
        // add the test's in the suite
        TestSuite suite = new TestSuite(TestJunit1.class, TestJunit2.class, TestJunit3.class );
        TestResult result = new TestResult();
        suite.run(result);
        System.out.println("Number of test cases = " + result.runCount());
    }
}

 输出:

No of Test Case = 1
Test Case Name = testAdd
Updated Test Case Name = testNewAdd
Number of test cases = 3


JUnit - 编写测试

在这里你会会看到一个应用POJO类,业务逻辑类和在测试运行器中运行的测试类的JUnit测试的例子。

public class EmployeeDetails {

   private String name;
   private double monthlySalary;
   private int age;

   /**
   * @return the name
   */
   public String getName() {
      return name;
   }
   /**
   * @param name the name to set
   */
   public void setName(String name) {
      this.name = name;
   }
   /**
   * @return the monthlySalary
   */
   public double getMonthlySalary() {
      return monthlySalary;
   }
   /**
   * @param monthlySalary the monthlySalary to set
   */
   public void setMonthlySalary(double monthlySalary) {
      this.monthlySalary = monthlySalary;
   }
   /**
   * @return the age
   */
   public int getAge() {
      return age;
   }
   /**
   * @param age the age to set
   */
   public void setAge(int age) {
   this.age = age;
   }
}

 EmployeeDetails类被用于

  • 取得或者设置雇员的姓名的值
  • 取得或者设置雇员的每月薪水的值
  • 取得或者设置雇员的年龄的值
public class EmpBusinessLogic {
   // Calculate the yearly salary of employee
   public double calculateYearlySalary(EmployeeDetails employeeDetails){
      double yearlySalary=0;
      yearlySalary = employeeDetails.getMonthlySalary() * 12;
      return yearlySalary;
   }

   // Calculate the appraisal amount of employee
   public double calculateAppraisal(EmployeeDetails employeeDetails){
      double appraisal=0;
      if(employeeDetails.getMonthlySalary() < 10000){
         appraisal = 500;
      }else{
         appraisal = 1000;
      }
      return appraisal;
   }
}

 EmpBusinessLogic类被用来计算

  • 雇员每年的薪水
  • 雇员的评估金额

 TestEmployeeDetails 被测试的测试案例类

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class TestEmployeeDetails {
   EmpBusinessLogic empBusinessLogic =new EmpBusinessLogic();
   EmployeeDetails employee = new EmployeeDetails();

   //test to check appraisal
   @Test
   public void testCalculateAppriasal() {
      employee.setName("Rajeev");
      employee.setAge(25);
      employee.setMonthlySalary(8000);
      double appraisal= empBusinessLogic.calculateAppraisal(employee);
      assertEquals(500, appraisal, 0.0);
   }

   // test to check yearly salary
   @Test
   public void testCalculateYearlySalary() {
      employee.setName("Rajeev");
      employee.setAge(25);
      employee.setMonthlySalary(8000);
      double salary= empBusinessLogic.calculateYearlySalary(employee);
      assertEquals(96000, salary, 0.0);
   }
}

 TestEmployeeDetails是用来测试EmpBusinessLogic类的方法的,它

  • 测试雇员的每年的薪水
  • 测试雇员的评估金额

 TestRunner 来执行测试案例类

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestEmployeeDetails.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
} 

 


JUnit - 使用断言

断言

所有的断言都包含在Assert类中

public class Assert extends java.lang.Object

 这个类提供了很多有用的断言方法来编写测试用例。只有失败的断言才会被记录。断言类中的一些有用的方法列式如下:

序号 方法和描述
1 void assertEquals(boolean expected,boolean actual)
检查两个变量或者等式是否平衡
2 void assertTrue(boolean expected,boolean actual)
检查条件为真
3 void assertFalse(boolean condition)
检查条件为假
4 void assertNotNull(Object object)
检查对象不为空
void assertNull(Object object)
检查对象为空
6 void assertSame(boolean condition)
assertSame()方法检查两个相关对象是否指向同一个对象
7 void assertNotSame(boolean condition)
assertNotSame()方法检查两个相关对象是否不指向同一个对象
8 void assertArrayEquals(expectedArray,resultArray)
assertArrayEquals()方法检查两个数组是否相等

 下面我们在例子中试验一下上面提到的各种方法。

import org.junit.Test;
import static org.junit.Assert.*;

public class TestAssertions {

   @Test
   public void testAssertions() {
      //test data
      String str1 = new String ("abc");
      String str2 = new String ("abc");
      String str3 = null;
      String str4 = "abc";
      String str5 = "abc";
      int val1 = 5;
      int val2 = 6;
      String[] expectedArray = {"one", "two", "three"};
      String[] resultArray =  {"one", "two", "three"};

      //Check that two objects are equal
      assertEquals(str1, str2);

      //Check that a condition is true
      assertTrue (val1 < val2);

      //Check that a condition is false
      assertFalse(val1 > val2);

      //Check that an object isn't null
      assertNotNull(str1);

      //Check that an object is null
      assertNull(str3);

      //Check if two object references point to the same object
      assertSame(str4,str5);

      //Check if two object references not point to the same object
      assertNotSame(str1,str3);

      //Check whether two arrays are equal to each other.
      assertArrayEquals(expectedArray, resultArray);
   }
}

 创建一个文件名为TestRunner.java的类来执行测试用例

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner2 {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestAssertions.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
} 

 


JUnit - 执行过程

注释

注释就好像你可以在你的代码中添加并且在方法或者类中应用的元标签。JUnit 中的这些注释为我们提供了测试方法的相关信息,哪些方法将会在测试方法前后应用,哪些方法将会在所有方法前后应用,哪些方法将会在执行中被忽略。
JUnit 中的注释的列表以及他们的含义:

序号 注释和描述
1 @Test
这个注释说明依附在 JUnit 的 public void 方法可以作为一个测试案例。
2 @Before
有些测试在运行前需要创造几个相似的对象。在 public void 方法加该注释是因为该方法需要在 test 方法前运行。
3 @After
如果你将外部资源在 Before 方法中分配,那么你需要在测试运行后释放他们。在 public void 方法加该注释是因为该方法需要在 test 方法后运行。
4 @BeforeClass
在 public void 方法加该注释是因为该方法需要在类中所有方法前运行。
5 @AfterClass
它将会使方法在所有测试结束后执行。这个可以用来进行清理活动。
6 @Ignore
这个注释是用来忽略有关不需要执行的测试的。

 

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class ExecutionProcedureJunit {
    //execute only once, in the starting
    @BeforeClass
    public static void beforeClass() {
        System.out.println("in before class");
    }

    //execute only once, in the end
    @AfterClass
    public static void afterClass() {
        System.out.println("in after class");
    }

    //execute for each test, before executing test
    @Before
    public void before() {
        System.out.println("in before");
    }

    //execute for each test, after executing test
    @After
    public void after() {
        System.out.println("in after");
    }

    //test case 1
    @Test
    public void testCase1() {
        System.out.println("in test case 1");
    }

    //test case 2
    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class TestRunner {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(ExecutionProcedureJunit.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

输出:

in before class
in before
in test case 1
in after
in before
in test case 2
in after
in after class
true

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class JunitFlowTest {
    /*
     * [email protected]修饰的方法会在所有方法被调用前被执行,而且该方法是静态的,所以当测试类被加载后接着就会运行它,而且在内存中它只会存在一份实例,它比较适合加载配置文件。
     * [email protected]所修饰的方法通常用来对资源的清理,如关闭数据库的连接
     * [email protected]和@After会在每个测试方法的前后各执行一次。
     *
     */
    @BeforeClass
    public static void setUpBeforeClass() {
        System.out.println("this is BeforeClass...");
    }

    @AfterClass
    public static void tearDownAfterClass() {
        System.out.println("this is AfterClass...");
    }

    @Before
    public void setUp() {
        System.out.println("this is Before...");
    }

    @After
    public void tearDown() {
        System.out.println("this is After...");
    }

    @Test
    public void test1() {
        System.out.println("this is test1...");
    }

    @Test
    public void test2(){
        System.out.println("this is test2...");
    }

}

输出:

this is BeforeClass...
this is Before...
this is test1...
this is After...

this is Before...
this is test2...
this is After...

this is AfterClass...

观察以上的输出,这是 JUnite 执行过程:

  • beforeClass() 方法首先执行,并且只执行一次。
  • afterClass() 方法最后执行,并且只执行一次。
  • before() 方法针对每一个测试用例执行,但是是在执行测试用例之前。
  • after() 方法针对每一个测试用例执行,但是是在执行测试用例之后。
  • 在 before() 方法和 after() 方法之间,执行每一个测试用例。

JUnit - 执行测试

测试用例JUnitCore类来执行的.JUnitCore是运行测试的外观类。它支持运行JUnit 4测试,JUnit 3.8.x测试,或者他们的混合。要从命令行运行测试,可以运行java org.junit。 runner.JUnitCore。对于只有一次的测试运行,可以使用静态方法runClasses(Class [])。

下面是org.junit.runner.JUnitCore类的声明:

public class JUnitCore extends java.lang.Object
/*
* This class prints the given message on console.
*/
public class MessageUtil {

   private String message;

   //Constructor
   //@param message to be printed
   public MessageUtil(String message){
      this.message = message;
   }

   // prints the message
   public String printMessage(){
      System.out.println(message);
      return message;
   }   
}  

 创建测试用例类

  • 创建一个java测试类叫做TestJunit.java。
  • 在类中加入一个测试方法testPrintMessage()。
  • 在方法testPrintMessage()中加入注释@Test。
  • 实现测试条件并且用Junit的assertEquals API检查测试条件。
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {

   String message = "Hello World";  
   MessageUtil messageUtil = new MessageUtil(message);

   @Test
   public void testPrintMessage() {
      assertEquals(message,messageUtil.printMessage());
   }
}

创建TestRunner类

创建一个java类文件命名为TestRunner.java来执行测试用例,导出JUnitCore类并且使用runClasses()方法,将测试类名称作为参数。

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}  

 


JUnit - 套件测试(批量运行测试类的方法)

测试套件

测试套件意味着捆绑几个单元测试用例并且一起执行他们。在JUnit中,@ RunWith@Suite注释用来运行套件测试。这个教程将向您展示一个例子,其中含有两个测试样例TestJunit1&TestJunit2类,我们将使用测试套件一起运行他们。

随着项目规模的增大,测试类也会越来越多,这个时候我们不可能一个一个的运行测试类,这个时候我们就可以把测试类集合到一个测试套件中,运行测试套件即可。测试有个特点套件,这个类是个空类。 

/*
* This class prints the given message on console.
*/
public class MessageUtil {

   private String message;

   //Constructor
   //@param message to be printed
   public MessageUtil(String message){
      this.message = message; 
   }

   // prints the message
   public String printMessage(){
      System.out.println(message);
      return message;
   }   

   // add "Hi!" to the message
   public String salutationMessage(){
      message = "Hi!" + message;
      System.out.println(message);
      return message;
   }   
}  
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestJunit1 {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Test
   public void testPrintMessage() { 
      System.out.println("Inside testPrintMessage()");    
      assertEquals(message, messageUtil.printMessage());     
   }
}
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestJunit2 {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Test
   public void testSalutationMessage() {
      System.out.println("Inside testSalutationMessage()");
      message = "Hi!" + "Robert";
      assertEquals(message,messageUtil.salutationMessage());
   }
}

 使用测试套件类

  • 创建一个java类。
  • 在类中附上@RunWith(Suite.class)注释。
  • 使用@ Suite.SuiteClasses注释给JUnit测试类加上引用。
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
   TestJunit1.class,
   TestJunit2.class
})
public class JunitTestSuite {   
}  

创建Test Runner类

创建一个java类文件叫做TestRunner.java来执行测试用例。

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(JunitTestSuite.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}  

 输出:

Inside testPrintMessage()
Robert
Inside testSalutationMessage()
Hi Robert
true

案例二

三个测试类: 

import org.junit.Test;
public class TaskTest1 {
	@Test
	public void test() {
		System.out.println("this is TaskTest1...");
	}
}
import org.junit.Test;
public class TaskTest2 {
	@Test
	public void test() {
		System.out.println("this is TaskTest2...");
	}
}
import org.junit.Test;
public class TaskTest3 {
	@Test
	public void test() {
		System.out.println("this is TaskTest3...");
	}
}

 测试套件:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({TaskTest1.class,TaskTest2.class,TaskTest3.class})
public class SuiteTest {
	/*
	 * 1.测试套件就是组织测试类一起运行的
	 * 写一个作为测试套件的入口类,这个类里不包含其他的方法
	 * 更改测试运行器Suite.class
	 * 将要测试的类作为数组传入到Suite.SuiteClasses({})
	 */
}

输出:

this is TaskTest1...
this is TaskTest2...
this is TaskTest3... 


JUnit - 忽略测试

有时可能会发生我们的代码还没有准备好的情况,这时测试用例去测试这个方法或代码的时候会造成失败。@Ignore注释会在这种情况时帮助我们。

  • 一个含有@Ignore注释的测试方法将不会被执行。
  • 如果一个测试类有@Ignore注释,则它的测试方法将不会执行。

现在我们用例子来学习@Ignore。

创建一个类

/*
* This class prints the given message on console.
*/
public class MessageUtil {

   private String message;

   //Constructor
   //@param message to be printed
   public MessageUtil(String message){
      this.message = message; 
   }

   // prints the message
   public String printMessage(){
      System.out.println(message);
      return message;
   }   

   // add "Hi!" to the message
   public String salutationMessage(){
      message = "Hi!" + message;
      System.out.println(message);
      return message;
   }   
} 

 创建测试用例类

  • 创建java测试类命名为TestJunit.java。
  • 在类中加入测试方法testPrintMessage()和testSalutationMessage()。
  • 在方法testPrintMessage()中加入@Ignore注释。
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestJunit {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Ignore
   @Test
   public void testPrintMessage() {
      System.out.println("Inside testPrintMessage()");
      message = "Robert";
      assertEquals(message,messageUtil.printMessage());
   }

   @Test
   public void testSalutationMessage() {
      System.out.println("Inside testSalutationMessage()");
      message = "Hi!" + "Robert";
      assertEquals(message,messageUtil.salutationMessage());
   }
}

 创建Test Runner类

创建一个java类文件叫做TestRunner.java来执行测试用例。

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}  

现在运行Test Runner类,即不会运行在Test Case类中定义的testPrintMessage()测试用例。 

验证输出.testPrintMessage()测试用例并没有被测试。

 输出:

Inside testSalutationMessage()
Hi!Robert
true 

 现在更新TestJunit在类级别上使用@Ignore来忽略所有的测试用例

import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

@Ignore
public class TestJunit {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Test
   public void testPrintMessage() {
      System.out.println("Inside testPrintMessage()");
      message = "Robert";
      assertEquals(message,messageUtil.printMessage());
   }

   @Test
   public void testSalutationMessage() {
      System.out.println("Inside testSalutationMessage()");
      message = "Hi!" + "Robert";
      assertEquals(message,messageUtil.salutationMessage());
   }
}

保持你的Test Runner不被改变,如下:

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}

 现在运行Test Runner即不会运行在Test Case类中定义的任何一个测试样例。

验证输出。没有测试用例被测试。

输出:

true


JUnit - 时间测试

 Junit的提供了一个暂停的方便选项。如果一个测试用例比起指定的毫秒数花费了更多的时间,那么Junit的将自动将它标记为失败。超时参数和@Test注释一起使用。现在让我们看看活动中的@test(超时)。

创建一个类

  • 创建MessageUtil.java的java类来测试。
  • 在printMessage()方法内添加一个无限而循环。
/*
* This class prints the given message on console.
*/
public class MessageUtil {

   private String message;

   //Constructor
   //@param message to be printed
   public MessageUtil(String message){
      this.message = message; 
   }

   // prints the message
   public void printMessage(){
      System.out.println(message);
      while(true);
   }   

   // add "Hi!" to the message
   public String salutationMessage(){
      message = "Hi!" + message;
      System.out.println(message);
      return message;
   }   
} 

 创建测试用例类

  • 创建一个叫做TestJunit.java的java测试类。
  • 给testPrintMessage()测试用例添加1000的暂停时间。

创建TestJunit类。

import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestJunit {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Test(timeout=1000)
   public void testPrintMessage() { 
      System.out.println("Inside testPrintMessage()");     
      messageUtil.printMessage();     
   }

   @Test
   public void testSalutationMessage() {
      System.out.println("Inside testSalutationMessage()");
      message = "Hi!" + "Robert";
      assertEquals(message,messageUtil.salutationMessage());
   }
}

 创建Test Runner类

创建一个文件名为TestRunne的java类来执行测试样例。

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
} 

 现在运行Test Runner,它将运行由提供的测试用例类中所定义的测试用例。

验证输出.testPrintMessage()测试用例将标记单元测试失败。

输出:

Inside testPrintMessage()
Robert
Inside testSalutationMessage()
Hi!Robert
testPrintMessage(TestJunit): test timed out after 1000 milliseconds
false

 


JUnit - 异常测试

Junit用代码处理提供了一个追踪异常的选项。你可以测试代码是否它抛出了想要得到的异常。预期参数和@Test注释一起使用。现在让我们看看活动中的@Test(预期)

创建一个类

/*
* This class prints the given message on console.
*/
public class MessageUtil {

   private String message;

   //Constructor
   //@param message to be printed
   public MessageUtil(String message){
      this.message = message; 
   }

   // prints the message
   public void printMessage(){
      System.out.println(message);
      int a =0;
      int b = 1/a;
   }   

   // add "Hi!" to the message
   public String salutationMessage(){
      message = "Hi!" + message;
      System.out.println(message);
      return message;
   }   
}  

 创建测试用例类

  • 创建一个叫做TestJunit.java的java测试类。
  • 给testPrintMessage()测试用例添加需要的异常ArithmeticException。

创建一个文件名为TestJunit.java的java类

import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestJunit {

   String message = "Robert";   
   MessageUtil messageUtil = new MessageUtil(message);

   @Test(expected = ArithmeticException.class)
   public void testPrintMessage() { 
      System.out.println("Inside testPrintMessage()");     
      messageUtil.printMessage();     
   }

   @Test
   public void testSalutationMessage() {
      System.out.println("Inside testSalutationMessage()");
      message = "Hi!" + "Robert";
      assertEquals(message,messageUtil.salutationMessage());
   }
}

 创建TestRunner类

创建一个文件名为TestJunit.java的java类来执行测试用例。

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}

 

现在运行Test Runner,它将运行由提供的测试用例类中所定义的测试用例。

 

验证输出.testPrintMessage()测试用例将通过。

输出:

Inside testPrintMessage()
Robert
Inside testSalutationMessage()
Hi!Robert
true

 


JUnit - 参数化测试

Junit 4引入了一个新的功能参数化测试。参数化测试允许开发人员使用不同的值反复运行同一个测试。你将遵循5个步骤来创建参数化测试

  • 用@RunWith(Parameterized.class)来注释测试类。
  • 创建一个由@Parameters注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
  • 创建一个公共的构造函数,它接受和一行测试数据相等同的东西。
  • 为每一列测试数据创建一个实例变量。
  • 用实例变量作为测试数据的来源来创建你的测试用例。

一旦每一行数据出现测试用例将被调用。让我们看看活动中的参数化测试。

创建一个类

创建一个叫做PrimeNumberChecker.java的java类来测试。

public class PrimeNumberChecker {
   public Boolean validate(final Integer primeNumber) {
      for (int i = 2; i < (primeNumber / 2); i++) {
         if (primeNumber % i == 0) {
            return false;
         }
      }
      return true;
   }
}

 创建参数化测试用例类

创建一个叫做PrimeNumberCheckerTest.java的java类。

import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.junit.Before;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;

@RunWith(Parameterized.class)
public class PrimeNumberCheckerTest {
   private Integer inputNumber;
   private Boolean expectedResult;
   private PrimeNumberChecker primeNumberChecker;

   @Before
   public void initialize() {
      primeNumberChecker = new PrimeNumberChecker();
   }

   // Each parameter should be placed as an argument here
   // Every time runner triggers, it will pass the arguments
   // from parameters we defined in primeNumbers() method
   public PrimeNumberCheckerTest(Integer inputNumber, 
      Boolean expectedResult) {
      this.inputNumber = inputNumber;
      this.expectedResult = expectedResult;
   }

   @Parameterized.Parameters
   public static Collection primeNumbers() {
      return Arrays.asList(new Object[][] {
         { 2, true },
         { 6, false },
         { 19, true },
         { 22, false },
         { 23, true }
      });
   }

   // This test will run 4 times since we have 5 parameters defined
   @Test
   public void testPrimeNumberChecker() {
      System.out.println("Parameterized Number is : " + inputNumber);
      assertEquals(expectedResult, 
      primeNumberChecker.validate(inputNumber));
   }
}

 创建TestRunner类

创建一个文件名为TestRunner.java的java类来执行测试用例

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(PrimeNumberCheckerTest.class);
      for (Failure failure : result.getFailures()) {
         System.out.println(failure.toString());
      }
      System.out.println(result.wasSuccessful());
   }
}

现在运行TestRunner,它将运行由提供的测试用例类中所定义的测试用例。 

输出:

Parameterized Number is : 2
Parameterized Number is : 6
Parameterized Number is : 19
Parameterized Number is : 22
Parameterized Number is : 23
true

案例二

public class Calculate {
	public int add(int a,int b) {
		return a + b;
	}
	public int subtract(int a, int b) {
		return a - b;
	}
	public int multiply(int a,int b) {
		return a * b;
	}
	public int divide(int a ,int b) {
		return a / b;
	}
}
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 {
	/*
	 * 1.更改默认的测试运行器为RunWith(Parameterized.class)
	 * 2.声明变量来存放预期值 和结果值
	 * 3.声明一个返回值 为Collection的公共静态方法,并使用@Parameters进行修饰
	 * 4.为测试类声明一个带有参数的公共构造函数,并在其中为之声明变量赋值
	 */
	int expected =0;
	int input1 = 0;
	int input2 = 0;
	
	@Parameters
	public static Collection<Object[]> t() {
		return Arrays.asList(new Object[][]{
				{3,1,2},
				{4,2,2}
		}) ;
	}
	
	public ParameterTest(int expected,int input1,int input2) {
		this.expected = expected;
		this.input1 = input1;
		this.input2 = input2;
	}
	
	@Test
	public void testAdd() {
		assertEquals(expected, new Calculate().add(input1, input2));
	}

}

 Junit4

 


 总结:

Junit4


  • 1.测试方法上必须使用@Test进行修饰
  • 2.测试方法必须使用public void 进行修饰,不能带任何的参数
  • 3.新建一个源代码目录来存放我们的测试代码
  • 4.测试类的包应该和被测试类保持一致
  • 5.测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖
  • 6.测试类使用Test作为类名的后缀(不是必须)
  • 7.测试方法使用test作为方法名的前缀(不是必须) 

测试失败的两种情况:  

  • 1.Failure一般由单元测试使用的断言方法判断失败所引起的,这经表示 测试点发现了问题 ,就是说程序输出的结果和我们预期的不一样。
  • 2.error是由代码异常引起的,它可以产生于测试代码本身的错误,也可以是被测试代码中的一个隐藏的bug
  • 3.测试用例不是用来证明你是对的,而是用来证明你没有错。 
import static org.junit.Assert.*;
import org.junit.Test;
public class ErrorAndFailureTest {
	/*
	 * 1.Failure一般由单元测试使用的断言方法判断失败所引起的,这经表示 测试点发现了问题
	 * ,就是说程序输出的结果和我们预期的不一样。
	 * 2.error是由代码异常引起的,它可以产生于测试代码本身的错误,也可以是被测试代码中的
	 * 一个隐藏的bug
	 * 3.测试用例不是用来证明你是对的,而是用来证明你没有错。
	 */
	@Test
	public void testAdd() {
		assertEquals(5, new Calculate().add(3,3));
	}

	@Test
	public void testDivide() {
		assertEquals(3, new Calculate().divide(6, 0));
	}
}

  • [email protected]修饰的方法会在所有方法被调用前被执行,而且该方法是静态的,所以当测试类被加载后接着就会运行它,而且在内存中它只会存在一份实例,它比较适合加载配置文件。
  • [email protected]所修饰的方法通常用来对资源的清理,如关闭数据库的连接
  • [email protected]和@After会在每个测试方法的前后各执行一次。