SpringBoot를 기반으로 프로젝트를 진행하였습니다.
Spring에서 Controller에 대해 Test 프로그래밍을 공부 하였다.
먼저 ControllerTest 파일을 만들게되면
@SpringBootTest
@AutoConfigureMockMvc
internal class BankControllerTest @Autowired constructor(
val mockMvc: MockMvc,
val objectMapper: ObjectMapper
)
이러한 양식으로 작성을 했습니다.
Test환경을 갖추기 위해 @SpringBootTest
와
mockMvc를 쓰기위해 @AutoConfigureMockMvc
를 사용했고
@Autowired
가 mockMvc와 objectMapper를 DI 하게 됩니다.
@Autowired
: 필요한 의존 객체의 “타입"에 해당하는 IoC 컨테이너 안에 존재하는 Bean을 찾아 주입합니다.
@Nested
@DisplayName("DELETE /api/banks/{accountNumber}")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
inner class DeleteExistingBank {
@Test
@DirtiesContext
fun `should delete the bank with the given account number`() {
// given
val accountNumber = 123456
// when/then
mockMvc.delete("$baseUrl/$accountNumber")
.andDo { print() }
.andExpect { status { isNoContent() } }
mockMvc.get("$baseUrl/$accountNumber")
.andExpect { status { isNotFound() } }
}
@Test
fun `should return NOT FOUND if no bank with given account number exists`() {
// given
val invalidAccountNumber = "does_not_exist"
// when/then
// mockMVC DSL
mockMvc.delete("$baseUrl/$invalidAccountNumber")
.andDo { print() }
.andExpect { status { isNotFound() } }
}
}
Spring Test에서 같은 context를 사용하는 테스트(같은 context.xml 파일을 이용해서 생성되거나,
같은 SpringBootApplication 이용)가 여러 개 있을 때 각각의 테스트마다 새로운 context를 생성하는게 아니라
기존의 context를 재활용하기 때문에 발생하는 문제습니다.
-> 따라서 그냥 단순히 inner class test로 테스트를 하게 되면 독립적인 테스트 환경을 구성을 못함!!
TDD 규칙중에 F.I.R.S.T 중 I (Isolated) 를 지키기 위해서
임시로 @DirtiesContext
를 Delete 수행 테스트 메소드에 적용하였습니다.
@DirtiesContext
: 어노테이션을 통해 테스트를 수행하기 전, 수행한 이후,@Nested
: 중첩 구조로 테스트 할 수 있게 만듬. (가독성 높이기 위해서 사용할 듯?)@DisplayName
: 중첩 구조의 이름 표시@TestInstance
: Test 인스턴스의 Lifecycle 결정.@Test
: 해당 메소드를 Test 수행 대상이 됨.가독성을 높이기 위해 mockMVC DSL을 사용하여 프로그래밍을 하였습니다.
@Test
fun `should add the new bank`() {
//given
val newBank = Bank("acc123", 31.415, 2)
//when
val performPost = mockMvc.post(baseUrl) {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(newBank)
}
// then
performPost
.andDo { print() }
.andExpect {
status { isCreated() }
content {
contentType(MediaType.APPLICATION_JSON)
json(objectMapper.writeValueAsString(newBank))
}
// jsonPath("$.accountNumber") { value("acc123") }
// jsonPath("$.trust") { value("31.415") }
// jsonPath("$.transactionFee") { value("2") }
}
mockMvc.get("$baseUrl/${newBank.accountNumber}")
.andExpect {
content { json(objectMapper.writeValueAsString(newBank)) } }
}
이런식으로
header 설정(contentType) 이라던지 body(content)를 설정하고
http통신을 수행할 수 있었습니다.
위와 같은 방식으로
getBanks, getBank, addBank, updateBank, deleteBank 에 대해서
Test를 진행하였습니다.
https://shortstories.gitbooks.io/studybook/content/dirtiescontext.html
https://www.youtube.com/watchv=TJcshrJOnsE&list=PL6gx4Cwl9DGDPsneZWaOFg0H2wsundyGr&index=2