テスト内容
RestControllerが返却するJSON形式のレスポンスボディを検証します。
環境
Spring Boot:2.1.1
Spock:1.2
Groovy:2.5
OS:Windows10
準備
Spring Boot + Spockのテストで必要なライブラリを追加します。spock-coreへの依存を書いておくことで、Groovy周りのライブラリも一緒に落ちてきます。また、spock-springがないとSpock(Groovy)の中で@Autowired等が使えないので、必要であればこれも追加しておきます。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.2-groovy-2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.2-groovy-2.5</version>
<scope>test</scope>
</dependency>
テストしたいRestControllerのURLとレスポンスボディ
テストしたいRestControllerのURLとレスポンスボディは以下のものとします。
URL:
http://localhost:8080/employees
Response:
Status Code 200 OK
[
{
"id": "00000001",
"name": "社員A",
"department": {
"id": "001",
"name": "部署A"
}
},
{
"id": "00000002",
"name": "社員B",
"department": {
"id": "001",
"name": "部署A"
}
}
]
テストしたいControllerクラス
EmployeeService#getEmployeesから先は省略しますが、テストしたいControllerとしては以下のような形です。
@RestController
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping(value = "/employees")
public ResponseEntity<List<Employee>> getEmployees() {
List<Employee> employeeList = employeeService.getEmployees();
if (CollectionUtils.isEmpty(employeeList)) {
return new ResponseEntity<>(null, HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Employee>>(employeeList, HttpStatus.OK);
}
}
テストクラス
GroovyのJsonSlurperとJsonBuilderを利用して検証します。
- Spring BootのテストでMockMvcを使う場合、テストクラスに@AutoConfigureMockMvcを付与します。そうすることで、@AutowiredでMockMvcのインジェクションが可能になります。
- 2つめのテストケースとして、レスポンスボディに何も設定されていないケースも書いてみます。そのため、そのケースのみ@SpyBeanを利用してEmployeeService#getEmployeesがnullを返すようスパイ化します(@MockBeanを利用すると、ケース1のEmployeeServiceもMock化されてしまうため)。
- @SpringBootTestを付与した場合、デフォルトではサーバーは起動しません。そのため、そのあたりを柔軟に対応したい場合はwebEnvironment属性を使用することになります(今回の例では使用しません)。
// ApplicationContextはロードするが、Web環境等は提供しない
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
// サーバーをランダムなポートで起動させる
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
// デフォルトはコレ、特に書かなくてもよい。サーバーを起動させず模擬Web環境が提供される
// @AutoConfigureMockMvcまたは@AutoConfigureWebTestClientと組み合わせて使用できる
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
// 実際のWeb環境が提供される。組み込みサーバーは起動し、設定されたポート(application.propertiesから)またはデフォルトのポート8080でlistenする
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
@SpringBootTest
@AutoConfigureMockMvc
class EmployeeControllerTest extends Specification {
@SpyBean
private EmployeeService employeeService
@Autowired
MockMvc mockMvc
@Unroll
def "EmployeeController - 正常系 - 2件の社員が返る"() {
given:
def department = new Department("001", "部署A");
def employeeList = new ArrayList<Employee>() { {
this.add(new Employee("00000001", "社員A", department));
this.add(new Employee("00000002", "社員B", department));
}
}
def jsonBuilder = new JsonBuilder(employeeList)
def jsonSlurper = new JsonSlurper()
when:
def actual = mockMvc.perform(MockMvcRequestBuilders.get("/employees")).andReturn().getResponse()
then:
actual.getStatus() == HttpStatus.OK.value
jsonSlurper.parseText(actual.getContentAsString()) == jsonSlurper.parseText(jsonBuilder.toPrettyString())
}
@Unroll
def "EmployeeController - 正常系 - 何も返らない"() {
given:
when(employeeService.getEmployees()).thenReturn(null)
when:
def actual = mockMvc.perform(MockMvcRequestBuilders.get("/employees")).andReturn().getResponse()
then:
actual.getStatus() == HttpStatus.NO_CONTENT.value
actual.getContentAsString() == ""
}
}
本記事では、JSONの検証にGroovyのJsonSlurperとJsonBuilderを利用しました。他の方法として、Spring Bootの@JsonTest等を利用してもJSONの検証は可能です。
本記事で使用したソース:https://github.com/kenichi-nagaoka/spock-sample/tree/feature/1
以上です。