https://www.youtube.com/watch?v=SFVWo0Z5Ppo&t=589s
https://goddaehee.tistory.com/210?category=367461
## 통합테스트
https://goddaehee.tistory.com/211?category=367461
https://goddaehee.tistory.com/212?category=367461
https://frozenpond.tistory.com/82
* 해당글이 설명이 잘 되어 있음
====================================================================================================
@WebMvcTest(테스트할 컨트롤러.class)
해당 클래스만 실제로 로드하여 테스트를 해줍니다.
아규먼트로 컨트롤러를 지정해주지 않으면 @Controller @RestController @ControllerAdvice 등등 컨트롤러와 연관된 bean들이 로드됩니다.
스프링의 모든 빈을 로드하여 테스트하는 방식인 @SpringBootTest어노테이션 대신 컨트롤러 관련 코드만 테스트하고자 할때 사용하는 어노테이션입니다.
MockMvc mvc;
컨트롤러의 api를 테스트하는 용도인 MockMvc 객체를 주입받습니다.
perform(httpMethod)로 실행하며 andExpect, andDo, andReturn등으로 동작을 확인하는 방식입니다.
@MockBean
MemberService memberService;
MemberController는 MemberService를 스프링컨테이너에서 주입받고있으므로
가짜 객체를 만들어 컨테이너가 주입할 수 있도록 해줍니다.
해당객체는 가짜객체이므로 실제 행위를 하는 객체가 아닙니다.
해당 객체 내부에서 의존하는 객체와 메서드들은 모두 가짜이며 실패하지만 않을뿐 기존에 정해진 동작을 수행하지 하지 않습니다.
given(memberService.list()).willReturn(members);
가짜객체가 원하는 행위를 할 수 있도록 정의해줍니다.(given when 등을 사용합니다.)
memberService의 list() 메서드를 실행시키면 members를 리턴해달라는 요청입니다.
andExpect(content().string(containsString("John")));
리턴받은 body에 John이라는 문자열이 존재하는지를 확인합니다.
given을 통해 mock객체의 예상한 행위가 정상적으로 동작했는지를 확인합니다.
verify(memberService).insert(member);
해당 메서드가 실행됐는지를 검증해줍니다.
====================================================================================================
아래는 실제로 컨트롤러, 서비스를 생성 한 뒤에
단위테스트를 진행해본 내용임
※ 블로그에 정리되어있지 않은 내용
mvc.perform( 이부분에는 httpMethod 뿐만이 아니라, 전달할 값과 전달할 값의 타입을 지정할 수 잇음 )
UnitTest.java
====================================================================================================
package com.example.demo.unitTest;
import static org.assertj.core.api.Assertions.assertThat;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import com.example.demo.testController.TestController;
import com.example.demo.testService.TestService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
//테스트를 할 컨트롤러를 지정
@WebMvcTest(TestController.class)
@Slf4j
public class UnitTest {
@Autowired
MockMvc mvc;
@MockBean
TestService testService;
@Test
@DisplayName("테스트 메소드 실행")
void excelTest() throws Exception{
log.info("test in");
String setString ="hihi";
given(testService.tempString(setString)).willReturn(setString);
System.out.println("#### 메소드호출" + testService.tempString(setString));
mvc.perform(get("/test").contentType("text/plain;charset=UTF-8").content(setString))
.andExpect(status().isOk())
.andExpect(content().string(containsString("hihi")));
String returnstring = testService.tempString(setString);
//assertThat(setString.equals("zz"));
System.out.println("#### 스트링출력" +returnstring);
}
}
====================================================================================================
TestService.java
====================================================================================================
package com.example.demo.testService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@AllArgsConstructor
@Service("testService")
public class TestService {
public String tempString(String str) {
log.info("##### str : {}" , str);
return str;
}
}
====================================================================================================
TestController.java
====================================================================================================
package com.example.demo.testController;
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.testService.TestService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@AllArgsConstructor
@RestController
public class TestController {
TestService testService;
@GetMapping("/test")
public String test(@RequestBody String str) {
String returnString = testService.tempString(str);
return returnString;
}
}
====================================================================================================
https://frozenpond.tistory.com/83?category=1175501
====================================================================================================
Mock vs MockBean
- 공통점
둘다 가짜객체이며 테스트스텁의 한 종류입니다.
given, when. verify 등을 사용하여 행위를 테스트합니다.
- 차이점
MockBean은 가짜 Bean을 스프링에 등록해달라는 의미입니다.
스프링 컨테이너가 기존에 갖고있는 Bean객체는 MockBean객체로 치환되어 DI에 사용됩니다.
Mock은 가짜객체를 만드는데 스프링빈에 등록이 안되는 객체입니다.
스프링 컨테이너가 DI를 하는 방식이 아니라 객체생성시 생성자에 Mock객체를 직접 주입해줍니다.
생성자 주입을 사용해야 편하게 사용 가능합니다
스프링을 띄우지 않으므로 MockBean을 사용할때보다 빠릅니다.
@BeforeEach
@Test 어노테이션이 붙은 메서드들이 실행되기 전에 실행되는 메서드입니다.
testService = new TestService();
TestService 직접 생성해줍니다.
직접 생성하므로 스프링 컨테이너의 도움을 전혀 받지 않습니다. 따라서 생성자주입에 사용했던 Repository나 Mapper 객체를 직접 주입해줘야합니다.
@Mock을 사용하여 mapper를 생성하여 서비스를 생성할때 직접 주입해줍니다.
MockitoAnnotations.initMocks(this);
@Mock이 붙은 객체를 생성, 초기화해달라는 명령입니다.
@SpringBootTest
통합테스트 방식으로 스프링을 실제 서버를 띄운것과 동일하게 띄워줍니다.
spring bean도 모두 로드되어서 메서드를 호출하면 DB까지 접근하지만
MockBean어노테이션을 사용하게되면 빈객체를 치환하여 DB에 접근하지 않게 됩니다.
스프링에 해당 객체를 빈으로 등록해달라는 요청입니다.
같은이름의 빈이 있었다면 MockBean으로 치환됩니다.
가짜객체를 만들어 서비스단을 테스트할때는
굳이 스프링을 띄울 필요가 없다면, MockBean이 아닌 Mock을 사용하는것이 비용이 훨씬 작습니다.
객체를 Autowired 받아서 생성하는방식(스프링을 띄우는 방식) 이 아니라면 직접 Mock 객체를 잡아서 테스트코드를 작성하는것이 빠릅니다.
@webMvcTest를 사용하여 컨트롤러를 테스트하는 경우를 제외하면 MockBean보다는 Mock을 사용하는게 좋을것 같습니다.
====================================================================================================