일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 메소드명
- ㅔㄴ션
- 참조키
- 네이티브쿼리
- application.yml
- querydsl
- WeNews
- appspec.yml
- 커밋메세지수정
- 포트
- Query
- 메세지수정
- docker명령어
- 2 > /dev/null
- 검색
- subquery
- 추후정리
- 테스트메소드
- 외부키
- appspec
- 컨테이너실행
- ubuntu
- 예약
- 적용우선순위
- 테스트
- 서브쿼리
- AuthenticationEntryPoint
- foreignkey
- EC2
- MySQL
- Today
- Total
제뉴어리의 모든것
[Section3] [Spring MVC] 테스팅(Testing) - 3 (Mockito) Service 계층을 끊은 Controller 테스트 본문
[Section3] [Spring MVC] 테스팅(Testing) - 3 (Mockito) Service 계층을 끊은 Controller 테스트
제뉴어리맨 2022. 9. 17. 15:03사전에 봐야할 포스트
https://januaryman.tistory.com/458
깃허브 주소
https://github.com/JanuaryKim/JanuaryKim-be-template-testing
Mockito란?
Java용 테스트 프레임워크이다.
테스트를 진행할때 필요한 기능을 제공하는 프레임워크인것이다.
+ Mock이란?
일상에서 쓰이는 용어는 mockup 과 비슷한 의미로,
프로그래밍상에 모의 객체라는 의미이다.
mockup은 실 생활에서 "실물 모형"이란 뜻이다.
mock 또한 프로그래밍상에서 진짜같은 가짜 객체를 말한다.
Mock 객체의 필요 이유
- 목 객체를 사용 안할때
- 목 객체를 사용 할때
위와 같이 만약 우리가 테스트할 대상이 Controller이라면
Controller의 핸들러 메소드만 테스트 해보면 될것이다.
그런데 만약 이후 계층까지 모두 통과하여 진행하게 되면,
Controller의 테스트를 통과하기 위해 서비스 계층과 데이터 액세스 계층까지 모두 완전히 로직을 완성하고 테스트를 해야할 것이다.
그리고 Controller - Service - Repository 를 다 거치는 Controller 에 대한 테스트라고 할 수도 없을 것이다.
그리고 각 계층들만 테스트 하면 될 일을,
만약 mock을 사용하여 각각의 계층을 끊어주지 않는다면
Controller 테스트할때는 Controller - Service - Repository,
Service 테스트 할때는 Service - Repository,
Repository 테스트 할때는 Repository,
이런 과정을 거쳐서 테스트를 해야한다.
그러나 mock 을 사용하여 테스트 한다면
Controller 테스트할때는 Controller,
Service 테스트 할때는 Service,
Repository 테스트 할때는 Repository,
이런식으로 각 계층만 테스트할 수 있으므로 성능면에서도 좋을 것이다.
그럼 진행 해보자.
build.gradle
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.codestates'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'com.google.code.gson:gson:2.9.0'
}
tasks.named('test') {
useJUnitPlatform()
}
예제 코드
아래의 내용은 Controller 레벨만을 테스트 하기 위해 Service 계층을 끊어준것이다.
Service 레벨은 given 을 이용하여 당연히 정상적인 결과를 돌려주도록 하였다.
import com.codestates.member.dto.MemberDto;
import com.codestates.member.entity.Member;
import com.codestates.member.mapper.MemberMapper;
import com.codestates.member.service.MemberService;
import com.codestates.stamp.Stamp;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerMockTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
// (1)
@MockBean
private MemberService memberService;
// (2)
@Autowired
private MemberMapper mapper;
@Test
void postMemberTest() throws Exception {
// given
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
"홍길동",
"010-1234-5678");
Member member = mapper.memberPostToMember(post); // (3)
member.setStamp(new Stamp()); // (4)
// (5)
given(memberService.createMember(Mockito.any(Member.class)))
.willReturn(member);
String content = gson.toJson(post);
// when
ResultActions actions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
// then
MvcResult result = actions
.andExpect(status().isCreated())
.andExpect(jsonPath("$.data.email").value(post.getEmail()))
.andExpect(jsonPath("$.data.name").value(post.getName()))
.andExpect(jsonPath("$.data.phone").value(post.getPhone()))
.andReturn();
// System.out.println(result.getResponse().getContentAsString());
}
}
이전 포스트에서 설명한 애노테이션 부분은 제외하겠다.
여기서 눈여겨 볼것은 (1), (5) 이다.
(1) :
import org.springframework.boot.test.mock.mockito.MockBean; 로 인해
@MockBean을 사용할 수 있는데,
MemberService 를 개발자가 만든 클래스로 빈 등록하는것이 아닌 임의의 가짜 클래스로 빈 등록을 하겠다는것이다.
말하자면 빈 이름은 MemberService이지만 그 안에 클래스 내용은 텅 비어 있는것이다.
아무것도 정의되어 있지 않다고 생각하면 된다.
그리고 @MockBean은 @SpringBootTest와 함께 쓰이는데, 그렇게 만들어진 가짜 빈을 스프링컨테이너에 넣어준다.
이것은 @Mock과 @MockBean의 결정적인 차이이다.
해당 내용은 위에 링크에 잘 나와 있으므로 이 정도로 하겠다.
(2) : @SpringBootTest로 인해 빈으로 정상 등록 되어있는 MemberMapper를 의존성 주입받는다
(3) : MemberMapper를 이용하여 DTO를 Entity로 변환
(4) : Member 엔티티와 1:1 연관관계가 맺어져 있는 Stamp 필드 세팅
(5) :
import static org.mockito.BDDMockito.given; 로 인해 사용 가능한 give() 정적 메소드로
텅 비어 있는 MemberService 안에 createMember() 메소드의 Input과 Output을 정해준다.
나머지 내용들은 이전 포스트의 내용과 거의 유사하다.
Stubbing이란?
Stubbing은 테스트를 위해서 Mock 객체가 항상 일정한 동작을 하도록 지정하는 것을 의미합니다
'코드스테이츠 > 정리 블로깅' 카테고리의 다른 글
[Section3]기술 면접 (0) | 2022.09.19 |
---|---|
[Section3] [Spring MVC] 테스팅(Testing) - 4 (Mockito) Service 계층에 Mockito 이용 테스트 (0) | 2022.09.18 |
[Section3] [Spring MVC] 테스팅(Testing) - 3 (데이터 액세스 계층 테스트) (0) | 2022.09.17 |
[Section3] [Spring MVC] 테스팅(Testing) - 2 (API 계층 테스트) (0) | 2022.09.17 |
[Section3] [Spring MVC] 트랜잭션(Transaction) (0) | 2022.09.07 |