【JUnit測試】總結

Nemo&發表於2020-07-20

什麼是Junit?

Junit是xUnit的一個子集,在c++,paython,java語言中測試框架的名字都不相同
xUnit是一套基於測試驅動開發的測試框架
其中的斷言機制:將程式預期的結果與程式執行的最終結果進行比對,確保對結果的可預知性
java所用的測試工具是Junit

使用 JUnit 需要匯入 JUnit 包。官方網站:https://junit.org/junit5/
在不同編譯器下的導包過程不一樣,這裡以 Maven 為例

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

測試流程

建立測試檔案

  1. 新建一個原始碼目錄來存放我們的測試程式碼
  2. 測試類的包應該和被測試類保持一致
  3. 測試方法上必須使用 @Test 進行修飾
  4. 測試方法必須使用 public void 進行修飾,不能帶任何的引數
  5. 測試單元中的每個方法必須可以獨立測試,測試方法間不能有任何的依賴
  6. 測試類使用 Test 作為類名的字尾(不是必須)
  7. 測試方法使用 test 作為方法名的字首(不是必須)

目的碼:

package com.imooc.util;

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;
    }
}

建立測試程式碼

右鍵選中需要測試的目的碼,建立 JUnit Test Case 測試用例。
【JUnit測試】總結
【JUnit測試】總結
【JUnit測試】總結
【JUnit測試】總結

測試程式碼:

package com.imooc.util;

import static org.junit.Assert.*;

import org.junit.Test;

public class CalculateTest {

    /*
     * 1.測試方法上必須使用@Test進行修飾
     * 2.測試方法必須使用public void 進行修飾,不能帶任何的引數
     * 3.新建一個原始碼目錄來存放我們的測試程式碼
     * 4.測試類的包應該和被測試類保持一致
     * 5.測試單元中的每個方法必須可以獨立測試,測試方法間不能有任何的依賴
     * 6.測試類使用Test作為類名的字尾(不是必須)
     * 7.測試方法使用test作為方法名的字首(不是必須)
     */
    @Test
    public void testAdd() {
        assertEquals(6, new Calculate().add(3,3));
    }
    
    @Test
    public void testSubtract() {
        assertEquals(3, new Calculate().subtract(5,2));
    }
    
    @Test
    public void testMultiply() {
        assertEquals(4, new Calculate().multiply(2, 2));
    }
    
    @Test
    public void testDivide() {
        assertEquals(3, new Calculate().divide(6, 2));
    }
}

【JUnit測試】總結
注意:

  1. Failure 一般由單元測試使用的斷言方法判斷失敗所引起的,這表示在測試點發現了問題,即 程式輸出的結果和我們預期的不一樣。
  2. error 是由程式碼異常引起的,它可以產生於測試程式碼本身的錯誤,也可以是被測試程式碼中的一個隱藏 bug。
  3. 測試用例不說用來證明你是對的,而是用來證明你沒有錯

註釋

演示程式碼:

package com.imooc.util;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class JunitFlowTest {

    /*
     * 1.@BeforeClass修飾的方法會在所有方法被呼叫前被執行,
     * 而且該方法是靜態的,所以當測試類被載入後接著就會執行它,
     * 而且在記憶體中它只會存在一份例項,它比較適合載入配置檔案。
     * 2.@AfterClass所修飾的方法通常用來對資源的清理,如關閉資料庫的連線
     * 3.@Before和@After會在每個測試方法的前後各執行一次。
     * 
     */
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("this is beforeClass...");
    }

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

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

    @After
    public void tearDown() throws Exception {
        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...");
    }

}

執行結果:
【JUnit測試】總結

隱藏的固定程式碼:

  1. @BeforeClass 修飾的方法會在所有方法被呼叫前被執行,而且該方法是靜態的,所以當測試類被載入後接著就會執行它,而且在記憶體中它只會存在一份例項,它比較適合載入配置檔案以及一些只用載入一次的東西。
  2. @AfterClass 所修飾的方法通常用來堆資源的清理,如關閉資料庫的連線
  3. @Before@After 會在每個測試方法的前後各執行一次。

    這些都是固定程式碼,執行時一定會被執行


常用註釋:

  • @Test:將一個普通的方法修飾成為一個測試方法
    • @Test(expected=XX.class)
    • @Test(timeout=毫秒)
  • @BeforeClass:它會在所有的方法執行前被執行,static 修飾
  • @AfterClass:它會在所有的方法執行結束後被執行,static 修飾
  • @Before:會在每一個測試方法被執行前執行一次
  • @After:會在每一個測試方法執行後被執行一次
  • @Ignore:所修飾的測試方法會被測試執行器忽略
  • @RunWith:可以更改測試執行器(如想自定義測試執行器可繼承 org.junit.runner.Runner)
    可以配合測試套件使用。

測試套件

測試套件:可以組織測試類一起執行。

  1. 寫一個作為測試套件的入口類,這個類裡不包含其他的方法
  2. 更改測試執行器為 @RunWith(Suite.class)
  3. 將要測試的類作為陣列傳入到 @Suite.SuiteClasses({A,B,...})

演示程式碼:

package com.imooc.util;

import static org.junit.Assert.*;

import org.junit.Test;
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({})
     */
}

這段程式碼可以將 TaskTest1、2、3 同時執行測試。從而達到測試套件的效果。

引數化設定

  1. 更改預設的測試執行器為 @RunWith(Parameterized.class)
  2. 宣告變數來存放預期值和結果值
  3. 宣告一個返回值為 Collection<> 的公共靜態方法,並使用 @Parameters 進行修飾
  4. 為測試類宣告一個帶有引數的公共建構函式,並在其中為之宣告變數賦值
  5. 編寫測試方法,使用變數

演示程式碼:

package com.imooc.util;

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;//輸入值1
    int input2 = 0;//輸入值2
    
    @Parameters //可以將返回的引數依次放入構造方法中進行測試
    public static Collection<Object[]> t() {
        return Arrays.asList(new Object[][]{
                {3,1,2},//預期值,輸入值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));
    }

}

在 Spring 中進行測試

Spring 配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
    </bean>
    <bean id="date" class="java.util.Date"/>
</beans>

Spring 測試程式碼

package com.imooc.conform;

import java.util.Date;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

    private static ApplicationContext context = null;
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void test() {
        Date date =  (Date) context.getBean("date");
        System.out.println(date);
    }
}