(轉)Spring Boot Junit單元測試

場景:在項目開發中要測試springboot工程中一個幾個dao和service的功能是否正常,初期是在web工程中進行要素的錄入,工做量太大。使用該單元測試大大減少了工做強度。java

Junit這種老技術,如今又拿出來講,不爲別的,某種程度上來講,更是爲了要說明它在項目中的重要性。
憑本人的感受和經驗來講,在項目中徹底按標準都寫Junit用例覆蓋大部分業務代碼的,應該不會超過一半。web

恰好前段時間寫了一些關於SpringBoot的帖子,正好如今把Junit再拿出來從幾個方面再說一下,也算是給一些新手參考了。spring

那麼先簡單說一下爲何要寫測試用例
1. 能夠避免測試點的遺漏,爲了更好的進行測試,能夠提升測試效率
2. 能夠自動測試,能夠在項目打包前進行測試校驗
3. 能夠及時發現由於修改代碼致使新的問題的出現,並及時解決數組

那麼本文從如下幾點來講明怎麼使用Junit,Junit4比3要方便不少,細節你們能夠本身瞭解下,主要就是版本4中對方法命名格式再也不有要求,再也不須要繼承TestCase,一切都基於註解實現。springboot

1 SpringBoot Web項目中中如何使用Junit

建立一個普通的Java類,在Junit4中再也不須要繼承TestCase類了。
由於咱們是Web項目,因此在建立的Java類中添加註解:框架

@RunWith(SpringJUnit4ClassRunner.class) // SpringJUnit支持,由此引入Spring-Test框架支持! 
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class) // 指定咱們SpringBoot工程的Application啓動類
@WebAppConfiguration // 因爲是Web項目,Junit須要模擬ServletContext,所以咱們須要給咱們的測試類加上@WebAppConfiguration。

接下來就能夠編寫測試方法了,測試方法使用@Test註解標註便可。
在該類中咱們能夠像日常開發同樣,直接@Autowired來注入咱們要測試的類實例。
下面是完整代碼:oop

package org.springboot.sample;

import static org.junit.Assert.assertArrayEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springboot.sample.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

/**
 *
 * @author   單紅宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年2月23日
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
@WebAppConfiguration
public class StudentTest {

    @Autowired
    private StudentService studentService;

    @Test
    public void likeName() {
        assertArrayEquals(
                new Object[]{
                        studentService.likeName("小明2").size() > 0,
                        studentService.likeName("壞").size() > 0,
                        studentService.likeName("莉莉").size() > 0
                    }, 
                new Object[]{
                        true,
                        false,
                        true
                    }
        );
//      assertTrue(studentService.likeName("小明2").size() > 0);
    }

}

 

接下來,你須要新增無數個測試類,編寫無數個測試方法來保障咱們開發完的程序的有效性。post

2 Junit基本註解介紹

//在全部測試方法前執行一次,通常在其中寫上總體初始化的代碼
@BeforeClass單元測試

//在全部測試方法後執行一次,通常在其中寫上銷燬和釋放資源的代碼 
@AfterClass測試

//在每一個測試方法前執行,通常用來初始化方法(好比咱們在測試別的方法時,類中與其餘測試方法共享的值已經被改變,爲了保證測試結果的有效性,咱們會在@Before註解的方法中重置數據)
@Before

//在每一個測試方法後執行,在方法執行完成後要作的事情
@After

// 測試方法執行超過1000毫秒後算超時,測試將失敗
@Test(timeout = 1000)

// 測試方法指望獲得的異常類,若是方法執行沒有拋出指定的異常,則測試失敗
@Test(expected = Exception.class)

// 執行測試時將忽略掉此方法,若是用於修飾類,則忽略整個類
@Ignore("not ready yet")
@Test

@RunWith
在JUnit中有不少個Runner,他們負責調用你的測試代碼,每個Runner都有各自的特殊功能,你要根據須要選擇不一樣的Runner來運行你的測試代碼。
若是咱們只是簡單的作普通Java測試,不涉及Spring Web項目,你能夠省略@RunWith註解,這樣系統會自動使用默認Runner來運行你的代碼。

3 參數化測試

Junit爲咱們提供的參數化測試須要使用 @RunWith(Parameterized.class)
然而由於Junit 使用@RunWith指定一個Runner,在咱們更多狀況下須要使用@RunWith(SpringJUnit4ClassRunner.class)來測試咱們的Spring工程方法,因此咱們使用assertArrayEquals 來對方法進行多種可能性測試即可。

下面是關於參數化測試的一個簡單例子:

package org.springboot.sample;

import static org.junit.Assert.assertTrue;

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 {

    private String name;
    private boolean result;

    /**
     * 該構造方法的參數與下面@Parameters註解的方法中的Object數組中值的順序對應
     * @param name
     * @param result
     */
    public ParameterTest(String name, boolean result) {
        super();
        this.name = name;
        this.result = result;
    }

    @Test
    public void test() {
        assertTrue(name.contains("小") == result);
    }

    /**
     * 該方法返回Collection
     *
     * @return
     * @author SHANHY
     * @create  2016年2月26日
     */
    @Parameters
    public static Collection<?> data(){
        // Object 數組中值的順序注意要和上面的構造方法ParameterTest的參數對應
        return Arrays.asList(new Object[][]{
            {"小明2", true},
            {"壞", false},
            {"莉莉", false},
        });
    }
}

4 打包測試

正常狀況下咱們寫了5個測試類,咱們須要一個一個執行。
打包測試,就是新增一個類,而後將咱們寫好的其餘測試類配置在一塊兒,而後直接運行這個類就達到同時運行其餘幾個測試的目的。

代碼以下:

@RunWith(Suite.class) 
@SuiteClasses({ATest.class, BTest.class, CTest.class}) 
public class ABCSuite {
    // 類中不須要編寫代碼
} 

5 使用Junit測試HTTP的API接口

咱們能夠直接使用這個來測試咱們的Rest API,若是內部單元測試要求不是很嚴格,咱們保證對外的API進行徹底測試便可,由於API會調用內部的不少方法,姑且把它當作是整合測試吧。

下面是一個簡單的例子

package org.springboot.sample;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

/**
 *
 * @author   單紅宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年2月23日
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
//@WebAppConfiguration // 使用@WebIntegrationTest註解須要將@WebAppConfiguration註釋掉
@WebIntegrationTest("server.port:0")// 使用0表示端口號隨機,也能夠具體指定如8888這樣的固定端口
public class HelloControllerTest {

    private String dateReg;
    private Pattern pattern;
    private RestTemplate template = new TestRestTemplate();
    @Value("${local.server.port}")// 注入端口號
    private int port;

    @Test
    public void test3(){
        String url = "http://localhost:"+port+"/myspringboot/hello/info";
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); 
        map.add("name", "Tom");  
        map.add("name1", "Lily");
        String result = template.postForObject(url, map, String.class);
        System.out.println(result);
        assertNotNull(result);
        assertThat(result, Matchers.containsString("Tom"));
    }

}

6 捕獲輸出

使用 OutputCapture 來捕獲指定方法開始執行之後的全部輸出,包括System.out輸出和Log日誌。
OutputCapture 須要使用@Rule註解,而且實例化的對象須要使用public修飾,以下代碼:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
//@WebAppConfiguration // 使用@WebIntegrationTest註解須要將@WebAppConfiguration註釋掉
@WebIntegrationTest("server.port:0")// 使用0表示端口號隨機,也能夠具體指定如8888這樣的固定端口
public class HelloControllerTest {

    @Value("${local.server.port}")// 注入端口號
    private int port;

    private static final Logger logger = LoggerFactory.getLogger(StudentController.class);

    @Rule
    // 這裏注意,使用@Rule註解必需要用public
    public OutputCapture capture = new OutputCapture();

    @Test
    public void test4(){
        System.out.println("HelloWorld");
        logger.info("logo日誌也會被capture捕獲測試輸出");
        assertThat(capture.toString(), Matchers.containsString("World"));
    }
}

關於Assert類中的一些斷言方法,都很簡單,本文再也不贅述。

可是在新版的Junit中,assertEquals 方法已經被廢棄,它建議咱們使用assertArrayEquals,旨在讓咱們測試一個方法的時候多傳幾種參數進行多種可能性測試。

相關文章
相關標籤/搜索