LoginSignup
7
9

More than 5 years have passed since last update.

Spring Boot + SpockでRestControllerのテストをサクッと書く

Posted at

テスト内容

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等が使えないので、必要であればこれも追加しておきます。

pom.xml
<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としては以下のような形です。

EmployeeController.java
@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)
EmployeeControllerTest.groovy
@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

以上です。

参考

7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9