[spring] 테스트 코드 - 예제 코드 By starseat 2023-02-02 16:52:51 java/spring Post Tags 지난번에 올렸던 [[spring] 테스트 코드](https://starseat.net/blog/view/133) 와는 별개로 실제 사용될만한 테스트 코드 를 작성하였다. 아래 테스트코드에서 사용하는 `assertj` 역시 `Jnuit`에서 자동으로 라이브러리 등록을 해줌. - `assertj` 장점 - `CoreMatchers` 와 달리 추가 라이브러리가 필요하지 않음. - `Jnuit` 의 `assertThat`을 쓰면 `is()` 와 같이 `CoreMatchers` 라이브러리 필요 - 자동완성이 좀 더 확실하게 지원됨 - 참고: [백기선 님의 AssertJ가 JUnit의 assertThat 보다 편리한 이유](https://www.youtube.com/watch?v=zLx_fI24UXM&t=408s) # Dto ```java import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; public class SampleDtoTest { @Test public void samleDtoTest() { // sampleDto => String name, int age // given String name = "test"; int age = 30; // when SampleDto dto = SampleDto.builder().name(name).age(age).build(); // then assertThat(dto.getName()).isEqualTo(name); assertThat(dto.getAge()).isEqualTo(amount); } } ``` # Repository - `@After` - 단위 테스트가 끝날 때마다 수행되는 메소드 지정 - 보통은 배포 전 전체 테스트를 수행할 때 테스트간 데이터 침범을 막기 위해 사용 - `@Save` - `id 값`이 없으면 **insert**. 있으면 **update** 쿼리 실행 ## SampleRepositoryTest ```java import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springwork.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) @SpringBootTest public class SampleRepositoryTest { @Autowired SampleRepository repository; @After public void clanUp() { repository.deleteAll(); } @Test @DisplayName("저장 및 조회 테스트") public void sampleSaveAndLoadTest() { // given Spring title = "테스트 타이틀"; Spring content = "테스트 내용"; repository.save(Posts.builder() .title(title) .content(content) .auther("starseat") .build()); // when List list = repository.findAll(); Posts post = list.get(0); // then assertThat(post.getTitle()).isEqualTo(title); assertThat(post.getContent()).isEqualTo(content); } } ``` ## PostRepositoryTest ### 기본 Entity ```java import lombok.Getter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.EntityListeners; import javax.persistence.MappedSupperclass; import java.time.LocalDateTime; @Getter @MappedSuperclass @EntityListeners(AuditingEntityListerner.class) public abstract class BaseTimeEntity { @CreatedDate private LocalDateTime createdDate; @LastModiiedDate private LocalDateTime modifiedDate; } ``` ```java import lombok.*; @ToString @Builder @Getter @NoArgsConstructor @AllArgsConstructor public class Posts extends BaseTimeEntity { private String title; private String content; private String author; ... } ``` #### Repository Test ```java ... public class PostRepositoryTest { @Test @DisplayName("등록 테스트 (시간 표시)") public void savePostTest() { // given LocalDateTime = now = LocalDateTime.of(2023, 2, 2, 0, 0, 0); repository.save(Posts.builder() .title("title") .content("content") .author("tester") .build()); // when List list = repository.findAll(); Posts post = list.get(0); // then System.out.println(" date >> create: " + post.getCreatedDate() + ", modified: " + post.getModifiedDate()); assertThat(post.getCreatedDate()).isAfter(now); assertThat(post.getModifiedDate()).isAfter(now); } } ``` # Controller - **jsonPath** - JSON 응답값을 필드별로 검증할 수 있는 메소드 - `$`를 기준으로 필드명 명시 ## Sample Controller ```java import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.context.junit4.SpringRunner; import org.springframework.boot.test.web.servlet.MockMvc; import org.springframework.boot.test.web.servlet.ResultActions; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) @WebMvcTest(controllers = HomeController.class) public class HomeControllerTest { @Autowired private MockMvc mvc; @Test public void hellTest() throws Exception { String hello = "hello"; mvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string(hello)); } @Test public void getSampleDtoTest() { String name = "test"; int age = 30; mvc .perform(get("/hello/sample-dto") .param("name", name) .param("age", String.valueOf(age))) .andExpect(status().isOk()) .andExpect(jsonPath("$.name", is(name)) .andExpect(jsonPath("$.age", is(age))); } } ``` ## PostController ```java import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springwork.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class PostsApiControllerTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private PostsRepository repository; @After public void tearDown() throws Exception { repository.deleteAll(); } @Test @DisplayName("Post 등록") public void savePostTest() throws Exception { // given String title = "test title"; String content = "test content"; PostsSaveRequestDto requestDto = PostSaveRequestDto.build() .title(title) .content(content) .author("tester") .build()); String url = "http://localhost:" + port + "/api/v1/posts"; // when ResponseEntity responseEntity = restTemplate.postForEntity(url, requestDto, Long.class); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isGraterThan(0L); List list = repository.findAll(); assertThat(list.get(0).getTitle()).isEqualTo(title); assertThat(list.get(0).getContent()).isEqualTo(content); } @Test @DisplayName("Post 수정") public void updatePostTest() throws Exception { // given String title = "test title"; String content = "test content"; Posts saved = repository.save(Posts.builder() .title(title) .content(content) .author("tester") .build()); Long updateId = saved.getId(); String expectedTitle = "title2"; String expectedContent = "content2"; PostsUpdatedRequestDto requestDto = PostsUpdatedRequestDto.build() .title(expectedTitle) .content(expectedContent) .build()); String url = "http://localhost:" + port + "/api/v1/posts/" + updateId; HttpEntity requestEntity = new HttpEntity<>(requestDto); // when ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, Long.class); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isGraterThan(0L); List list = repository.findAll(); assertThat(list.get(0).getTitle()).isEqualTo(expectedTitle); assertThat(list.get(0).getContent()).isEqualTo(expectedContent); } } ``` # 참조 - [스프링 부트와 AWS로 혼자 구현하는 웹 서비스](https://jojoldu.tistory.com/463) Previous Post [spring] 자주 사용하는 어노테이션 (작성 중) Next Post [spring] iBatis 와 MyBatis 결과 차이