Spring Test

原文鏈接:

https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testing-introduction

測試

Spring團隊明確提倡采用TDD的方式進行軟件開發(fā),因此在單元測試的最佳實踐的同時也涵蓋了spring對集成測試的支持。spring團隊已經(jīng)發(fā)現(xiàn)正確的使用IoC確實可以簡化單元測試和集成測試(在IoC中類里面的setter方法和合理的構(gòu)造器的存在,能夠使得類很容易組裝在一個測試用例中,而不用手動的將service注冊(或者其他的類似操作)在一起。這一章僅僅沉浸在測試能夠給你提供的方便上。

1.簡介

測試是企業(yè)軟件開發(fā)的一個完整的組成部分。這個章節(jié)聚焦于IoC的原則為單元測試提供的附加價值,和獲得Spring框架為集成測試的支持的好處上。(對企業(yè)應(yīng)用軟件完整的測試治理機制遠遠超出于這個參照手冊的范圍。)

2.單元測試

相對于傳統(tǒng)的J2EE開發(fā)方式,DI能夠減少代碼對容器的依賴。構(gòu)成應(yīng)用的POJOs應(yīng)該在Junit或TestNG中具備可測試性,這種可測試性僅僅是通過使用new操作進行對象實例化,而不需要依賴于Spring或者其他的容器。你可以通過mock對象的方式,對代碼進行獨立的測試。如果您遵循Spring的架構(gòu)建議,那么代碼庫的清晰分層和組件化將簡化單元測試。例如,你可以通過打樁或者mock Dao接口的方式來測試你的service層,而不需要在運行單元測試的時候獲取持久層的數(shù)據(jù)。

因為沒有創(chuàng)建運行時環(huán)境,真正意義上的單元測試能夠以相當(dāng)快的方式運行。強調(diào)一下,作為你開發(fā)方法論的一部分,真正的單元測試能夠有效的提升你的生產(chǎn)力。你可能不需要這個測試的章節(jié)來幫助你針對你的基于IoC的應(yīng)用編寫有效的測試用例。但是本章這種描述了在某些單元測試的場景,Spring框架提供了mock對象和測試支持類。

2.1 mock對象

Spring提供了一組專注于mock的包:

  • Environment
  • JNDI
  • Servlet API
  • Spring Web Reactive

2.1.1 Environment

org.springframework.mock.env包提供了對Environment and PropertySource這兩個抽象mock實現(xiàn)。MockEnvironment and MockPropertySource 在針對特定環(huán)境的代碼,開發(fā)脫離容器的測試用例的時候非常實用。

2.1.2 JNDI

org.springframework.mock.jndi包含了JNDI SPI的實現(xiàn),通過它你可以為Test suits和stand-alone應(yīng)用構(gòu)建一個簡單的JNDI的環(huán)境 。例如,如果JDBC數(shù)據(jù)源實例綁定了J2EE容器相同的JNDI的名字,那么你可以在測試場景中,在沒有修改的情況下,復(fù)用代碼和配置。

2.1.3. Servlet API

org.springframework.mock.web包包含了一個綜合的Servlet API mock對象的集合,這可以用于測試web contexts, controllers, 和filters. 與通過 EasyMock 進行動態(tài)的mock對象或者通過MockObjects進行完整的Servlet API的mock對象相比,這些通過使用spring web mvc框架mock的對象通常更加方便。

從spring5開始,org.springframework.mock.web包中mock的對象是基于servlet 4.0的標準。

Spring MVC Test framework基于mock Servlet API objects 為Spring MVC提供了一個完成的測試框架。詳情參見 Spring MVC Test.

2.1.4. Spring Web Reactive

未完待續(xù)......

2.2 單元測試支持類

Spring提供了一組來支持單元測試,它們分布在兩個不同的目錄中。

2.2.1 General Testing Utilities

未完待續(xù)......

2.2.2. Spring MVC Testing Utilities

3.集成測試

這個章節(jié)(占了大量的攝于篇幅)覆蓋了Spring應(yīng)用的集成測試。它包括以下的主題:

  • 概述
  • 集成測試的目標
  • JDBC測試支持
  • 注解
  • Spring TestContext Framework
  • Spring MVC Test Framework
  • PetClinic Example

3.1 概述

未完待續(xù)......

3.2 集成測試的目標

Spring集成測試支持包括如下幾個目標:

  • 管理測試用例之間Spring IoC容器的緩存
  • 提供測試目標實例的依賴注入
  • 為集成測試提供事務(wù)管理
  • 為開發(fā)者在編寫集成測試用例是提供spring特性的基礎(chǔ)類
    以下的四個小結(jié)將闡述每一個目標,并且提供相應(yīng)的實現(xiàn)細節(jié)和配置細節(jié)的鏈接。

3.2.1 管理測試用例之間Spring IoC容器的緩存

Test classes typically declare either an array of resource locations for XML or Groovy configuration metadata?—?often in the classpath?—?or an array of annotated classes that is used to configure the application. These locations or classes are the same as or similar to those specified in web.xml or other configuration files for production deployments.

By default, once loaded, the configured ApplicationContext is reused for each test. Thus, the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term “test suite” means all tests run in the same JVM?—?for example, all tests run from an Ant, Maven, or Gradle build for a given project or module. In the unlikely case that a test corrupts the application context and requires reloading (for example, by modifying a bean definition or the state of an application object) the TestContext framework can be configured to reload the configuration and rebuild the application context before executing the next test.

See Context Management and Context Caching with the TestContext framework.
Spring TestContext Framework包含spring ApplicationContext實例和WebApplicationContext實例的加載,同時還包括了上下文的緩存。對加載上下文的緩存支持是十分重要的,因為啟動的時間可以變?yōu)閕ssue級別,當(dāng)然這不是因為覆蓋整個spring本身,而是因為spring的IoC容器對對象的實例化是要消耗時間的。例如一個項目包含50到100個Hibernater映射文件可能需要消耗10到20秒來加載映射文件,并且需要注意的是,在運行每一個測試用了之前的代價導(dǎo)致導(dǎo)致減慢所有的測試用例的運行,這將降低開發(fā)人員的生產(chǎn)力。

3.2.2 提供測試目標實例的依賴注入

3.2.3 為集成測試提供事務(wù)管理

3.2.4 為開發(fā)者在編寫集成測試用例是提供spring特性的基礎(chǔ)類

3.3 JDBC測試支持

未完待續(xù)......

3.4 注解

未完待續(xù)......

3.5 Spring TestContext Framework

未完待續(xù)......

3.6 Spring MVC Test Framework

Spring MVC Test framework通過適用于JUnit、TestNG或者其他測試框架的流式api,為測試Spring MVC的代碼提供了支持. 這是基于 spring-test模塊的 Servlet API mock objects ,因此不需要運行Servlet容器。它使用DispatcherServlet 提供完整的Spring MVC運行時行為,并且在standalone模式的基礎(chǔ)上,通過TestContext framework 為加載實際的Spring 配置提供支持,standalone模式中controllers能夠手動實例化并且每次只測試一個。

Spring MVC Test 也為測試 RestTemplate的代碼提供客戶端的支持??蛻舳藴y試mock了server端的相應(yīng),并且不需要運行服務(wù)端。

Spring Boot 提供了一個完整的運行server的端到端集成測試的選項。如果你也有相同的訴求,請移步到 Spring Boot reference page。了解更多的關(guān)于out-of-container 和end-to-end integration 測試, 詳見 Differences between Out-of-Container and End-to-End Integration Tests.

3.6.1. Server-Side Tests

通過JUnit或TestNG為Controller寫一個簡單的測試用例很容易 : 簡單的實例化Controller、注入mock對象或者打樁的依賴、傳遞MockHttpServletRequest, MockHttpServletResponse調(diào)用方法等等。但是,寫這樣一個單元測試用例依然有很多內(nèi)容沒有測試,如:request mappings、data binding、type conversion、 validation等等。甚至@InitBinder, @ModelAttribute, and @ExceptionHandler也是在請求處理的生命周期中。
Spring MVC Test的目標是通過真實的DispatcherServlet來執(zhí)行requests和生成responses,來為測試controller提供一個有效的方式。
這是一個基于JUnit Jupiter的使用Spring MVC Test的例子:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringJUnitWebConfig(locations = "test-servlet-context.xml")
class ExampleTests {

    private MockMvc mockMvc;

    @BeforeEach
    void setup(WebApplicationContext wac) {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    void getAccount() throws Exception {
        this.mockMvc.perform(get("/accounts/1")
                .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.name").value("Lee"));
    }
}

這個測試用例是基于TestContext framework對WebApplicationContext的支持,來加載同包中的xml配置文件的。當(dāng)然,Java-based和Groovy-based形式的配置也是支持的,詳情請見 sample tests
The jsonPath syntax is supported through the Jayway JsonPath project. Many other options for verifying the result of the performed request are discussed later in this document.
這個MockMvc實例演示了一個/accounts/1的GET請求,并且校驗了響應(yīng)的狀態(tài)是200, content type是application/json,響應(yīng)體有一個key=name,value= Lee的JSON屬性。jsonPath的語法是基于Jayway JsonPath project的標準。后續(xù)的文檔將會描述很多其他的驗證結(jié)果的選項。

Static Imports

前面的測試用例中fluent API需要一些Static Imports,例如 MockMvcRequestBuilders.、 MockMvcResultMatchers.和 MockMvcBuilders.*。 如果使用Eclipse或者基于Eclipse的 Spring Tool Suite,需要在Eclipse的preferences → Java → Editor → Content Assist → Favorites添加為 “favorite static members” 。這樣能夠在橋下這些api的首字母時,進行相應(yīng)的輔助提示。 其他IDEs (如:IntelliJ) 可能不需要附加的配置.然后檢查static members的代碼的自動補全支持。

Setup Choices

有兩種方式用于創(chuàng)建MockMvc實例,第一種是通過TestContext framework加載Spring MVC 的配置,這種方式加載Spring的配置并且將WebApplicationContext注入到測試用例中,從而構(gòu)建MockMvc實例。示例如下:

@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration("my-servlet-context.xml")
public class MyWebTests {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    // ...

}

第二種方式是在不加字啊spring配置的情況下,手動創(chuàng)建controller實例。基礎(chǔ)默認配置自動創(chuàng)建,這相當(dāng)于MVC JavaConfig 和MVC namespace??梢栽谝欢ǔ潭壬献粤x定配置。示例如下:

public class MyWebTests {

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
    }

    // ...

}

到底選擇哪種方式呢?
webAppContextSetup的方式加載了真實的Spring MVC 配置,結(jié)果就是更加完整的集成測試。因為TestContext framework緩存了Spring 已經(jīng)加載的配置,這有助于更加快速的測試,即使test suite中有很多的tests。
也可以通過Spring配置將mock Service 注入到 controller中,來保證聚焦在web層的測試。示例如下:

<!--聲明mock service-->
<bean id="accountService" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="org.example.AccountService"/>
</bean>
//將mock servcie 注入到 測試用例中。
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration("test-servlet-context.xml")
public class AccountTests {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Autowired
    private AccountService accountService;

    // ...

}

另一方面standaloneSetup的方式更接近于單元測試。這種方式每次只測試一個controller,并且可以手動注入mock依賴到controller中,而不涉及加載Spring配置。這種方式更專注于style,更容易看出正在被測試的controller,不管Sping MVC的配置等是否生效. standaloneSetup的模式對于ad-hoc(點對點)的測試和調(diào)試問題是一種非常方便的方式。
關(guān)于集成測試還是單元測試的討論是沒有對與錯之分的,但是使用standaloneSetup 的方式暗示了補充webAppContextSetup的測試的必要性??傊梢允褂脀ebAppContextSetup的方式,編寫全部的測試用例,來保證總是對Spring MVC 進行測試。

Setup Features

Performing Requests

Defining Expectations

Filter Registrations

Differences Between Out-of-Container and End-to-End Integration Tests

Further Server-Side Test Examples

3.6.2. HtmlUnit Integration

3.6.3. Client-Side REST Tests

3.7 PetClinic Example

未完待續(xù)......

4. 擴展資源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容