Spring Boot中的測試

簡介

本篇文章我們將會探討一下怎麼在SpringBoot使用測試,Spring Boot有專門的spring-boot-starter-test,通過使用它可以很方便的在Spring Boot進行測試。

本文將從repository,service, controller,app四個層級來詳細描述測試案例。

添加maven依賴

<code>

<

dependency

>

<

groupId

>

org.springframework.boot

groupId

>

<

artifactId

>

spring-boot-starter-test

artifactId

>

<

scope

>

test

scope

>

dependency

>

<

dependency

>

<

groupId

>

com.h2database

groupId

>

<

artifactId

>

h2

artifactId

>

<

scope

>

test

scope

>

dependency

>

/<code>

我們添加spring-boot-starter-test和com.h2database總共兩個依賴。H2數據庫主要是為了測試方便。

Repository測試

本例中,我們使用JPA,首先創建Entity和Repository:

<code>

@Entity

@Table

(name =

"person"

) public class Employee {

@Id

@GeneratedValue

(strategy = GenerationType.AUTO) private Long id;

@Size

(min =

3

, max =

20

) private String name; } /<code>
<code> 

public

interface

EmployeeRepository

extends

JpaRepository

<

Employee

,

Long

>

{

public

Employee

findByName

(String name)

; } /<code>

測試JPA,我們需要使用@DataJpaTest:

<code>

@RunWith

(SpringRunner.class)

@DataJpaTest

public class EmployeeRepositoryIntegrationTest {

@Autowired

private TestEntityManager entityManager;

@Autowired

private EmployeeRepository employeeRepository; } /<code>

@RunWith(SpringRunner.class) 是Junit和Spring Boot test聯繫的橋樑。

@DataJpaTest為persistence layer的測試提供瞭如下標準配置:

  • 配置H2作為內存數據庫
  • 配置Hibernate, Spring Data, 和 DataSource
  • 實現@EntityScan
  • 開啟SQL logging

下面是我們的測試代碼:

<code> 

public

void

whenFindByName_thenReturnEmployee

()

{ Employee alex =

new

Employee(

"alex"

); entityManager.persist(alex); entityManager.flush(); Employee found = employeeRepository.findByName(alex.getName()); assertThat(found.getName()) .isEqualTo(alex.getName()); } /<code>

在測試中,我們使用了TestEntityManager。 TestEntityManager提供了一些通用的對Entity操作的方法。上面的例子中我們使用TestEntityManager向Employee插入了一條數據。

Service測試

在實際的應用程序中,Service通常要使用到Repository。但是在測試中我們可以Mock一個Repository,而不用使用真實的Repository。

先看一下Service:

<code> 

public

class

EmployeeServiceImpl

implements

EmployeeService

{

private

EmployeeRepository employeeRepository;

public

Employee

getEmployeeByName

(String name)

{

return

employeeRepository.findByName(name); } } /<code>

我們再看一下怎麼Mock Repository。

<code> (SpringRunner

.

class

)

public

class

EmployeeServiceImplIntegrationTest

{

static

class

EmployeeServiceImplTestContextConfiguration

{

public

EmployeeService

employeeService

()

{

return

new

EmployeeServiceImpl(); } }

private

EmployeeService employeeService;

private

EmployeeRepository employeeRepository; } /<code>

看下上面的例子,我們首先使用了@TestConfiguration專門用在測試中的配置信息,在@TestConfiguration中,我們實例化了一個EmployeeService Bean,然後在
EmployeeServiceImplIntegrationTest自動注入。

我們還是用了@MockBean,用來Mock一個EmployeeRepository。

我們看下Mock的實現:

<code>     
    

public

void

setUp

()

{ Employee alex =

new

Employee(

"alex"

); Mockito.when(employeeRepository.findByName(alex.getName())) .thenReturn(alex); }

public

void

whenValidName_thenEmployeeShouldBeFound

()

{ String name =

"alex"

; Employee found = employeeService.getEmployeeByName(name); assertThat(found.getName()) .isEqualTo(name); } /<code>

上面的代碼中,我們使用Mockito來Mock要返回的數據,然後在接下來的測試中使用。

測試Controller

和測試Service一樣,Controller使用到了Service:

<code>

@RestController

@RequestMapping

(

"/api"

) public class EmployeeRestController {

@Autowired

private EmployeeService employeeService;

@GetMapping

(

"/employees"

) public List getAllEmployees() {

return

employeeService

.getAllEmployees

(); } } /<code>

但是在測試的時候,我們並不需要使用真實的Service,我們需要Mock它 。

<code>

@RunWith

(SpringRunner.class)

@WebMvcTest

(EmployeeRestController.class) public class EmployeeControllerIntegrationTest {

@Autowired

private MockMvc mvc;

@MockBean

private EmployeeService service; /<code>

為了測試Controller,我們需要使用到@WebMvcTest,他會為Spring MVC 自動配置所需的組件。

通常情況下@WebMvcTest 會和@MockBean一起使用來提供Mock的具體實現。

@WebMvcTest也提供了自動配置的MockMvc,它為測試MVC Controller提供了更加簡單的方式,而不需要啟動完整的HTTP server。

<code>@

Test

public

void

givenEmployees_whenGetEmployees_thenReturnJsonArray

(

) throws Exception

{ Employee alex =

new

Employee(

"alex"

); List allEmployees = Arrays.asList(alex); given(service.getAllEmployees()).willReturn(allEmployees); mvc.perform(

get

(

"/api/employees"

) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath(

"$"

, hasSize(

1

))) .andExpect(jsonPath(

"$[0].name"

,

is

(alex.getName()))); } /<code>

given(service.getAllEmployees()).willReturn(allEmployees); 這一行代碼提供了mock的輸出。方面後面的測試使用。

@SpringBootTest的集成測試

上面我們講的都是單元測試,這一節我們講一下集成測試。

<code>

@RunWith

(SpringRunner.class)

@SpringBootTest

( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestApplication.class)

@AutoConfigureMockMvc

@TestPropertySource

( locations =

"classpath:application-integrationtest.properties"

) public class EmployeeAppIntegrationTest {

@Autowired

private MockMvc mvc;

@Autowired

private EmployeeRepository repository; } /<code>

集成測試需要使用@SpringBootTest,在@SpringBootTest中可以配置webEnvironment,同時如果我們需要自定義測試屬性文件可以使用@TestPropertySource。

下面是具體的測試代碼:

<code>   @

After

public

void

resetDb

(

)

{ repository.deleteAll(); } @

Test

public

void

givenEmployees_whenGetEmployees_thenStatus200

(

) throws Exception

{ createTestEmployee(

"bob"

); createTestEmployee(

"alex"

); mvc.perform(

get

(

"/api/employees"

).contentType(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(jsonPath(

"$"

, hasSize(greaterThanOrEqualTo(

2

)))) .andExpect(jsonPath(

"$[0].name"

,

is

(

"bob"

))) .andExpect(jsonPath(

"$[1].name"

,

is

(

"alex"

))); }

private

void

createTestEmployee

(

String name

)

{ Employee emp =

new

Employee(name); repository.saveAndFlush(emp); } /<code>

歡迎關注我的公眾號:程序那些事,更多精彩等著您!

更多內容請訪問:flydean的博客 flydean.com


Spring Boot中的測試


分享到:


相關文章: