Writing Integration Tests for a REST API With Kotlin and JUnit 5: Writing Data

After we have finished this lesson, we understand how we can an write integration tests for a REST API that writes data to the database.

Get the source code from Github

Introduction to the System Under Test

During this lesson we will write integration tests for a controller function which processes POST requests send to the path: ‘/api/task’. This function inserts a new task into the database and returns the information of the created task as JSON.

When the system under tests saves a new task to the database, it follows these steps:

  1. Read the information of the created task from the request body and validate the information. If validation fails, return the HTTP status code 400 (bad request) and return the validation errors as JSON.
  2. Get the authenticated user (a UserDetails object) from the security context.
  3. Save a new task to the database.
  4. Return the HTTP status code 201 (created) and return the information of the created task as JSON.

The source code of our controller class looks as follows:

 1import org.springframework.beans.factory.annotation.Autowired
 2import org.springframework.http.HttpStatus
 3import org.springframework.security.core.annotation.AuthenticationPrincipal
 4import org.springframework.web.bind.annotation.*
 5import javax.validation.Valid
 6
 7@RestController
 8@RequestMapping("/api/task")
 9open class TaskCrudController(
10        @Autowired private val service: TaskCrudService
11) {
12
13    @RequestMapping(method = [RequestMethod.POST])
14    @ResponseStatus(HttpStatus.CREATED)
15    fun create(
16            @RequestBody @Valid input: CreateTaskDTO,
17            @AuthenticationPrincipal loggedInUser: LoggedInUser
18    ): TaskDTO {
19        return service.create(input, loggedInUser)
20    }
21}

The validation errors are processed by the TaskErrorHandler class. Its implementation doesn’t belong to the scope of this lesson, but it’s useful to know what kind of a JSON document is returned to the client if validation fails. For example, if the client tries to create a new task that has no title, the following JSON document is returned to the client:

1{
2    "fieldErrors":[
3        {
4            "field":"title",
5            "errorCode":"NotBlank"
6        }
7    ]
8}

The CreateTaskDTO class contains the information of the created task and specifies the validation rules which are used to validate the input data provided to the system under test. Its source code looks as follows:

1data class CreateTaskDTO(
2        @field: NotBlank
3        @field: Size(max = 100)
4        val title: String?,
5        @field: Size(max = 500)
6        val description: String?)

After the system under test has inserted a new task into the database, it returns the following JSON document back to client:

 1{
 2  "creator": {
 3    "name": "John Doe",
 4    "userId": 1
 5  },
 6  "description": "This lesson talks about integration testing",
 7  "id": 1,
 8  "modifier": {
 9    "name": "John Doe",
10    "userId": 1
11  },
12  "status": "OPEN",
13  "tags": [],
14  "title": "Write lesson"
15}

Next, we will configure the system under test.

Configuring the System Under Test

During this lesson we will write integration tests which verify that the system under test is working as expected when a normal user provides valid information to the system under test. We can configure the system under test by following these steps:

First, we have to add one constant to our test class. This constant specifies the id of the created task. After we have added this constant to our test class, its source code looks as follows:

 1import org.junit.jupiter.api.DisplayName
 2import org.springframework.beans.factory.annotation.Autowired
 3import org.springframework.test.web.servlet.MockMvc
 4
 5@WebIntegrationTest
 6@DisplayName("Create a new task by using valid information")
 7class CreateNewTaskWithValidInformationApiTest (
 8        @Autowired private val mockMvc: MockMvc
 9) {
10
11    companion object {
12
13        private val NEXT_FREE_ID = 1L
14    }
15
16    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
17}

Second, we have to add a private read-only property to our test class. This property contains an IdColumnReset object that can reset the auto-increment columns of the specified database tables. We can add this property to our test class by following these steps:

  1. Add a private read-only property called jdbcTemplate to our test class and inject the value of this property by using constructor injection. This property contains a NamedParameterJdbcTemplate object which allows us to reset the auto-increment column of the tasks database table.
  2. Add the IdColumnReset property to our test class.

After we have added this property to our test class, its source code looks as follows:

 1import org.junit.jupiter.api.DisplayName
 2import org.springframework.beans.factory.annotation.Autowired
 3import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 4import org.springframework.test.web.servlet.MockMvc
 5
 6@WebIntegrationTest
 7@DisplayName("Create a new task by using valid information")
 8class CreateNewTaskWithValidInformationApiTest (
 9        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
10        @Autowired private val mockMvc: MockMvc
11) {
12
13    companion object {
14
15        private val NEXT_FREE_ID = 1L
16    }
17
18    private val idColumnReset = IdColumnReset(jdbcTemplate)
19
20    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
21}

Third, we have to add a private read-only property to our test class. This property contains the input that’s provided to the system under test. After we have added this property to our test class, its source code looks as follows:

 1import org.junit.jupiter.api.DisplayName
 2import org.springframework.beans.factory.annotation.Autowired
 3import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 4import org.springframework.test.web.servlet.MockMvc
 5
 6@WebIntegrationTest
 7@DisplayName("Create a new task by using valid information")
 8class CreateNewTaskWithValidInformationApiTest (
 9        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
10        @Autowired private val mockMvc: MockMvc
11) {
12
13    companion object {
14
15        private val NEXT_FREE_ID = 1L
16    }
17
18    private val idColumnReset = IdColumnReset(jdbcTemplate)
19
20    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
21
22    private val INPUT = CreateTaskDTO(
23            description = Tasks.WriteLesson.DESCRIPTION,
24            title = Tasks.WriteLesson.TITLE
25    )
26}

The Tasks class is a constant class that contains the test data which is used by our integration tests. Its source code looks as follows:

 1class Tasks {
 2
 3    class WriteLesson {
 4
 5        companion object {
 6
 7            const val ID = 2L;
 8            const val CREATOR_ID = 1L
 9            const val DESCRIPTION = "This lesson talks about integration testing";
10            const val TITLE = "Write lesson"
11            val STATUS = TaskStatus.OPEN
12        }
13    }
14}

Fourth, we have to write a setup function that’s run before a test function is run. Our implementation of this function must reset the auto-increment column of the tasks database table. After we have written this function, the source code of our test class looks as follows:

 1import org.junit.jupiter.api.BeforeEach
 2import org.junit.jupiter.api.DisplayName
 3import org.springframework.beans.factory.annotation.Autowired
 4import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 5import org.springframework.test.web.servlet.MockMvc
 6
 7@WebIntegrationTest
 8@DisplayName("Create a new task by using valid information")
 9class CreateNewTaskWithValidInformationApiTest (
10        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
11        @Autowired private val mockMvc: MockMvc
12) {
13
14    companion object {
15
16        private val NEXT_FREE_ID = 1L
17    }
18
19    private val idColumnReset = IdColumnReset(jdbcTemplate)
20
21    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
22
23    private val INPUT = CreateTaskDTO(
24            description = Tasks.WriteLesson.DESCRIPTION,
25            title = Tasks.WriteLesson.TITLE
26    )
27
28    @BeforeEach
29    fun resetIdColumn() {
30        idColumnReset.resetIdColumns("tasks")
31    }
32}

Fifth, we have to create the inner class that contains the test functions which ensure that the system test is working as expected when a normal user provides valid information to the system under test.

After we have created this inner class, the source code of our test class looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.junit.jupiter.api.BeforeEach
 5import org.junit.jupiter.api.DisplayName
 6import org.junit.jupiter.api.Nested
 7import org.springframework.beans.factory.annotation.Autowired
 8import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 9import org.springframework.security.test.context.support.WithUserDetails
10import org.springframework.test.web.servlet.MockMvc
11
12@WebIntegrationTest
13@DisplayName("Create a new task by using valid information")
14class CreateNewTaskWithValidInformationApiTest (
15        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
16        @Autowired private val mockMvc: MockMvc
17) {
18
19    companion object {
20
21        private val NEXT_FREE_ID = 1L
22    }
23
24    private val idColumnReset = IdColumnReset(jdbcTemplate)
25
26    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
27
28    private val INPUT = CreateTaskDTO(
29            description = Tasks.WriteLesson.DESCRIPTION,
30            title = Tasks.WriteLesson.TITLE
31    )
32
33    @BeforeEach
34    fun resetIdColumn() {
35        idColumnReset.resetIdColumns("tasks")
36    }
37
38    @Nested
39    @WebIntegrationTest
40    @DatabaseSetup(value = [
41        "/com/testwithspring/master/users.xml",
42        "/com/testwithspring/master/no-tasks-and-tags.xml"
43    ])
44    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
45    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
46    @DisplayName("When the user is John Doe")
47    inner class WhenUserIsJohnDoe {
48
49    }
50}

The DbUnit data set (users.xml) which inserts the user data into our database looks as follows:

 1<dataset>
 2    <user_accounts id="1"
 3                   email_address="john.doe@gmail.com"
 4                   is_enabled="true"
 5                   name="John Doe"
 6                   password="user"
 7                   role="ROLE_USER"/>
 8    <user_accounts id="2"
 9                   email_address="anne.admin@gmail.com"
10                   is_enabled="true"
11                   name="Anne Admin"
12                   password="admin"
13                   role="ROLE_ADMIN"/>
14</dataset>

The DbUnit data set (no-tasks-and-tags.xml) which ensures that our database has no tasks and tags looks as follows:

1<dataset>
2    <tasks/>
3    <tags/>
4    <tasks_tags/>
5</dataset>

The Users class is a constant class which contains the test data found from the user_accounts table. The relevant part of its source code looks as follows:

 1class Users {
 2
 3    class JohnDoe {
 4
 5        companion object {
 6            const val ID = 1L
 7            const val EMAIL_ADDRESS = "john.doe@gmail.com"
 8            const val NAME = "John Doe"
 9        }
10    }
11}
The example application of this lesson contains integration tests which ensure that the system under test is working as expected when the user is anonymous or when the authenticated user is an administrator. If you want to take a look at these test functions, you should get the example application from Github .

Let’s move on and write integration tests for our controller function.

Writing Integration Tests for Our Controller Function

We can write integration tests for our controller function by following these steps:

First, we have verify that the system under test uses the next free id when it inserts a new task into the database. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.annotation.ExpectedDatabase
 4import com.github.springtestdbunit.assertion.DatabaseAssertionMode
 5import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    private inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should use the next free id when a new task is saved to the database")
54        @ExpectedDatabase(
55                value = "/com/testwithspring/master/task/create-task-id-expected.xml",
56                assertionMode = DatabaseAssertionMode.NON_STRICT
57        )
58        fun shouldUseNextFreeIdWhenNewTaskIsSavedToDatabase() {
59            requestBuilder.create(INPUT)
60        }
61    }
62}

The DbUnit data set (create-task-id-expected.xml) which ensures that system under test uses the next free id when it saves a new task to the database looks as follows:

1<dataset>
2    <tasks id="1"/>
3</dataset>

Second, we have to ensure that the system under test inserts the correct lifecycle column values into the database. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.annotation.ExpectedDatabase
 4import com.github.springtestdbunit.assertion.DatabaseAssertionMode
 5import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should insert correct lifecycle column values into the database")
54        @ExpectedDatabase(
55                value = "create-task-lifecycle-columns-johndoe-expected.xml",
56                assertionMode = DatabaseAssertionMode.NON_STRICT
57        )
58        fun shouldInsertCorrectLifecycleColumnValuesIntoDatabase() {
59            requestBuilder.create(INPUT)
60        }
61    }
62}

The DbUnit data set (create-task-lifecycle-columns-johndoe-expected.xml) which ensures that the system under test inserts the correct lifecycle column values into the database looks as follows:

1<dataset>
2    <tasks assignee_id="[null]"
3           closer_id="[null]"
4           creator_id="1"
5           modifier_id="1"/>
6</dataset>

Third, we have to verify that the system under test saves the correct status and resolution to the database. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.annotation.ExpectedDatabase
 4import com.github.springtestdbunit.assertion.DatabaseAssertionMode
 5import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should save the correct status and resolution to the database")
54        @ExpectedDatabase(
55                value = "/com/testwithspring/master/task/create-task-status-expected.xml",
56                assertionMode = DatabaseAssertionMode.NON_STRICT
57        )
58        fun shouldSaveCorrectStatusAndResolutionToDatabase() {
59            requestBuilder.create(INPUT)
60        }
61    }
62}

The DbUnit data set (create-task-status-expected.xml) which ensures that the system under test saves the correct status and resolution to the database looks as follows:

1<dataset>
2    <tasks resolution="[null]"
3           status="OPEN"/>
4</dataset>

Fourth, we have to ensure that the system under test inserts the correct title and description into the database. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.annotation.ExpectedDatabase
 4import com.github.springtestdbunit.assertion.DatabaseAssertionMode
 5import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should insert the correct title and description to the database")
54        @ExpectedDatabase(
55                value = "/com/testwithspring/master/task/create-task-title-description-expected.xml",
56                assertionMode = DatabaseAssertionMode.NON_STRICT
57        )
58        fun shouldInsertCorrectTitleAndDescriptionToDatabase() {
59            requestBuilder.create(INPUT)
60        }
61    }
62}

The DbUnit data set (create-task-title-description-expected.xml) which ensures that the system under test inserts the correct title and description into the database looks as follows:

1<dataset>
2    <tasks description="This lesson talks about integration testing"
3           title="Write lesson"/>
4</dataset>

Fifth, we have to verify that the system under test creates a task that has no tags. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.annotation.ExpectedDatabase
 4import com.github.springtestdbunit.assertion.DatabaseAssertionMode
 5import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should create a task that has no tags")
54        @ExpectedDatabase(
55                value = "/com/testwithspring/master/task/create-task-tags-expected.xml",
56                assertionMode = DatabaseAssertionMode.NON_STRICT
57        )
58        fun shouldCreateTaskThatHasNoTags() {
59            requestBuilder.create(INPUT)
60        }
61    }
62}

The DbUnit data set (create-task-tags-expected.xml) which verifies that the system under test creates a task that has no tags looks as follows:

1<dataset>
2    <tags/>
3    <tasks_tags/>
4</dataset>

Sixth, we have to ensure that the system under test returns the HTTP status code 201. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.junit.jupiter.api.BeforeEach
 5import org.junit.jupiter.api.DisplayName
 6import org.junit.jupiter.api.Nested
 7import org.junit.jupiter.api.Test
 8import org.springframework.beans.factory.annotation.Autowired
 9import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
10import org.springframework.security.test.context.support.WithUserDetails
11import org.springframework.test.web.servlet.MockMvc
12import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
13
14@WebIntegrationTest
15@DisplayName("Create a new task by using valid information")
16class CreateNewTaskWithValidInformationApiTest (
17        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
18        @Autowired private val mockMvc: MockMvc
19) {
20
21    companion object {
22
23        private val NEXT_FREE_ID = 1L
24    }
25
26    private val idColumnReset = IdColumnReset(jdbcTemplate)
27
28    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
29
30    private val INPUT = CreateTaskDTO(
31            description = Tasks.WriteLesson.DESCRIPTION,
32            title = Tasks.WriteLesson.TITLE
33    )
34
35    @BeforeEach
36    fun resetIdColumn() {
37        idColumnReset.resetIdColumns("tasks")
38    }
39
40    @Nested
41    @WebIntegrationTest
42    @DatabaseSetup(value = [
43        "/com/testwithspring/master/users.xml",
44        "/com/testwithspring/master/no-tasks-and-tags.xml"
45    ])
46    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
47    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
48    @DisplayName("When the user is John Doe")
49    inner class WhenUserIsJohnDoe {
50
51        @Test
52        @DisplayName("Should return the HTTP status code created")
53        fun shouldReturnHttpStatusCodeCreated() {
54            requestBuilder.create(INPUT)
55                    .andExpect(status().isCreated)
56        }
57    }
58}

Seventh, we have to ensure that the system under test returns the information of the created task as JSON. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.junit.jupiter.api.BeforeEach
 5import org.junit.jupiter.api.DisplayName
 6import org.junit.jupiter.api.Nested
 7import org.junit.jupiter.api.Test
 8import org.springframework.beans.factory.annotation.Autowired
 9import org.springframework.http.MediaType
10import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
11import org.springframework.security.test.context.support.WithUserDetails
12import org.springframework.test.web.servlet.MockMvc
13import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
14
15@WebIntegrationTest
16@DisplayName("Create a new task by using valid information")
17class CreateNewTaskWithValidInformationApiTest (
18        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
19        @Autowired private val mockMvc: MockMvc
20) {
21
22    companion object {
23
24        private val NEXT_FREE_ID = 1L
25    }
26
27    private val idColumnReset = IdColumnReset(jdbcTemplate)
28
29    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
30
31    private val INPUT = CreateTaskDTO(
32            description = Tasks.WriteLesson.DESCRIPTION,
33            title = Tasks.WriteLesson.TITLE
34    )
35
36    @BeforeEach
37    fun resetIdColumn() {
38        idColumnReset.resetIdColumns("tasks")
39    }
40
41    @Nested
42    @WebIntegrationTest
43    @DatabaseSetup(value = [
44        "/com/testwithspring/master/users.xml",
45        "/com/testwithspring/master/no-tasks-and-tags.xml"
46    ])
47    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
48    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
49    @DisplayName("When the user is John Doe")
50    inner class WhenUserIsJohnDoe {
51
52        @Test
53        @DisplayName("Should return the information of the created task as Json")
54        fun shouldReturnInformationOfCreatedTaskAsJson() {
55            requestBuilder.create(INPUT)
56                    .andExpect(content().contentType(MediaType.APPLICATION_JSON))
57        }
58    }
59}

Eigth, we have to verify that the system under test returns the information of the created task. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.equalTo
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return the information of the created task")
55        fun shouldReturnInformationOfCreatedTask() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath("$.id", equalTo(NEXT_FREE_ID.toInt())))
58        }
59    }
60}

Ninth, we have ensure that the system under test returns a task that has no assignee. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.nullValue
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return a task that has no assignee")
55        fun shouldReturnTaskThatHasNoAssignee() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath("$.assignee", nullValue()))
58        }
59    }
60}

Tenth, we have to verify that the system under test returns a task that has no closer. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.nullValue
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return a task that has no closer")
55        fun shouldReturnTaskThatHasNoCloser() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath("$.closer", nullValue()))
58        }
59    }
60}

Eleventh, we have to ensure that the system under test returns the information of the person who created the task. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.equalTo
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return the the information of the person who created the task")
55        fun shouldReturnCorrectCreator() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath(
58                            "$.creator.name",
59                            equalTo(Users.JohnDoe.NAME))
60                    )
61                    .andExpect(jsonPath(
62                            "$.creator.userId",
63                            equalTo(Users.JohnDoe.ID.toInt()))
64                    )
65        }
66    }
67}

Twelfth, we have to ensure that the system under test returns the information of the person who modified the task. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.equalTo
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return the the information of the person who modified the task")
55        fun shouldReturnCorrectModifier() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath(
58                            "$.modifier.name",
59                            equalTo(Users.JohnDoe.NAME))
60                    )
61                    .andExpect(jsonPath(
62                            "$.modifier.userId",
63                            equalTo(Users.JohnDoe.ID.toInt()))
64                    )
65        }
66    }
67}

Thirteenth, we have to verify that the system under test returns the correct description and title. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.equalTo
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return the correct description and title")
55        fun shouldReturnCorrectDescriptionAndTitle() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath(
58                            "$.description",
59                            equalTo(Tasks.WriteLesson.DESCRIPTION))
60                    )
61                    .andExpect(jsonPath(
62                            "$.title",
63                            equalTo(Tasks.WriteLesson.TITLE))
64                    )
65        }
66    }
67}

Fourteenth, we have to ensure that the system under test returns an open task. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.equalTo
 5import org.hamcrest.Matchers.nullValue
 6import org.junit.jupiter.api.BeforeEach
 7import org.junit.jupiter.api.DisplayName
 8import org.junit.jupiter.api.Nested
 9import org.junit.jupiter.api.Test
10import org.springframework.beans.factory.annotation.Autowired
11import org.springframework.http.MediaType
12import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
13import org.springframework.security.test.context.support.WithUserDetails
14import org.springframework.test.web.servlet.MockMvc
15import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
16
17@WebIntegrationTest
18@DisplayName("Create a new task by using valid information")
19class CreateNewTaskWithValidInformationApiTest (
20        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
21        @Autowired private val mockMvc: MockMvc
22) {
23
24    companion object {
25
26        private val NEXT_FREE_ID = 1L
27    }
28
29    private val idColumnReset = IdColumnReset(jdbcTemplate)
30
31    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
32
33    private val INPUT = CreateTaskDTO(
34            description = Tasks.WriteLesson.DESCRIPTION,
35            title = Tasks.WriteLesson.TITLE
36    )
37
38    @BeforeEach
39    fun resetIdColumn() {
40        idColumnReset.resetIdColumns("tasks")
41    }
42
43    @Nested
44    @WebIntegrationTest
45    @DatabaseSetup(value = [
46        "/com/testwithspring/master/users.xml",
47        "/com/testwithspring/master/no-tasks-and-tags.xml"
48    ])
49    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
50    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
51    @DisplayName("When the user is John Doe")
52    inner class WhenUserIsJohnDoe {
53
54        @Test
55        @DisplayName("Should return an open task")
56        fun shouldReturnOpenTask() {
57            requestBuilder.create(INPUT)
58                    .andExpect(jsonPath("$.resolution", nullValue()))
59                    .andExpect(jsonPath(
60                            "$.status",
61                            equalTo(Tasks.WriteLesson.STATUS.name))
62                    )
63        }
64    }
65}

Fifteenth, we have to verify that the system under test returns a task that has no tags. After we have written our test function, its source code looks as follows:

 1import com.github.springtestdbunit.annotation.DatabaseSetup
 2import com.github.springtestdbunit.annotation.DbUnitConfiguration
 3import com.github.springtestdbunit.dataset.ReplacementDataSetLoader
 4import org.hamcrest.Matchers.hasSize
 5import org.junit.jupiter.api.BeforeEach
 6import org.junit.jupiter.api.DisplayName
 7import org.junit.jupiter.api.Nested
 8import org.junit.jupiter.api.Test
 9import org.springframework.beans.factory.annotation.Autowired
10import org.springframework.http.MediaType
11import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
12import org.springframework.security.test.context.support.WithUserDetails
13import org.springframework.test.web.servlet.MockMvc
14import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
15
16@WebIntegrationTest
17@DisplayName("Create a new task by using valid information")
18class CreateNewTaskWithValidInformationApiTest (
19        @Autowired private val jdbcTemplate: NamedParameterJdbcTemplate,
20        @Autowired private val mockMvc: MockMvc
21) {
22
23    companion object {
24
25        private val NEXT_FREE_ID = 1L
26    }
27
28    private val idColumnReset = IdColumnReset(jdbcTemplate)
29
30    private val requestBuilder = TaskCrudRequestBuilder(mockMvc)
31
32    private val INPUT = CreateTaskDTO(
33            description = Tasks.WriteLesson.DESCRIPTION,
34            title = Tasks.WriteLesson.TITLE
35    )
36
37    @BeforeEach
38    fun resetIdColumn() {
39        idColumnReset.resetIdColumns("tasks")
40    }
41
42    @Nested
43    @WebIntegrationTest
44    @DatabaseSetup(value = [
45        "/com/testwithspring/master/users.xml",
46        "/com/testwithspring/master/no-tasks-and-tags.xml"
47    ])
48    @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class)
49    @WithUserDetails(Users.JohnDoe.EMAIL_ADDRESS)
50    @DisplayName("When the user is John Doe")
51    inner class WhenUserIsJohnDoe {
52
53        @Test
54        @DisplayName("Should return a task that has no tags")
55        fun shouldReturnTaskThatHasNoTags() {
56            requestBuilder.create(INPUT)
57                    .andExpect(jsonPath("$.tags", hasSize<Any>(0)))
58        }
59    }
60}

We can now write integration tests for a REST API that writes data to the database. Let’s summarize what we learned from this lesson.

Summary

This lesson has taught us two things:

  • We can reset the auto-increment column of a database table by using the NamedParameterJdbcTemplate class.
  • If we use small DbUnit data sets, we can write integration tests which assert one logical concept.

Get the source code from Github