Mockito

김나쁜 Kimbad·2024년 7월 25일
0

TDD

목록 보기
2/2

Mockito?

단위 테스트를 위해 모의 객체를 생성하고 관리하는 데 사용되는 Java 오픈 소스 프레임워크를 의미한다.

실제 객체의 동작을 모방하는 모의 객체(Mock Object)를 생성하여 코드의 특정 부분을 격리시키고 테스트 하기 쉽게 만들어 준다.

주로 단일 컴포넌트의 동작을 테스트 하는데 사용되며 클래스 내의 개별 메서드나 함수, 서로 다른 클래스 또는 컴포넌트 간의 상호작용, 객체들 간의 협업 등을 테스트 할 수 있다.

[!info]
모의 객체란 실제 사용되는 객체 생성을 대체하기 위해 테스트에 사용 되는 객체를 의미한다.
일반적으로 모의 객체의 변수 값은 null, 0, false와 같은 기본 타입의 값이 반환되며 메서드는 기본적으로 null로 구성된다.

Mockito를 사용하며 '모의 객체'와 함께 서비스를 호출 해 비즈니스 로직이 올바르게 처리가 되는지 확인하기 위한 테스트를 수행한다.
이러한 테스트 과정을 통해 서비스의 비즈니스 로직에 대해 검증하고 예외 상황에 대한 처리를 확인한다.

Mockito 수행 과정

이러한 흐름은 @Test를 수행하는 TestMethod()라는 메서드에서 서비스 호출을 위해 getCodeList() 함수를 호출하지만 DB에서 데이터를 조회해오지 않는 형태가 된다.

E2E(End to end) 테스트에서는 직접적으로 서비스 레이어, DB와 연계해서 테스트를 하게 되지만 단순한 비즈니스 로직 테스트의 경우 DB 종속을 끊고 모의 객체를 구성하여 테스트를 하게 된다.

모의 객체의 업무 수행 순서는 모의 객체 생성(Mock) → 메서드 호출 예상 동작 설정(Stub) → 메서드 호출 검증(Verify) 의 단계로 수행한다.

  1. 모의 객체 생성(Mock)
    • Mockito를 사용하여 테스트에 필요한 Mock 데이터를 생성한다.
    • 해당 객체는 실제 객체와 동일한 방식으로 동작하지만, 해당 동작을 사전에 정의할 수 있다.
  2. 메서드 호출 예상 동작 설정(Stub)
    • 모의 객체의 메서드 호출에 대한 '예상 동작'을 정의한다.
  3. 메서드 호출 검증(Verify)
    • 모의 객체에 대해 특정 메서드가 호출되고 예상된 인자와 함께 호출되었는지를 검증하는 메드를 제공한다.
@Test
void Mock_테스트() {
	// 1. 모의 객체 생성 (Mock)
	// 리스트 클래스를 Mocking하여 List처럼 동작하는 모의 객체 생성
	List<String> mockList = Mockito.mock(List.class);

	// 2. 메서드 (Stub)
	// 모의 객체의 특정 메서드를 호출했을 때 예상 동작을 설정한다.
	Mockito.when(mockList.size()).thenReturn(5);
	log.info("Mock Size : {}", mockList.size()); // :: 5

	// 메서드 호출 검증 : Verify
	Mockito.verify(mockList).size();
}

Mockito 주요 용어 및 요약

용어분류설명
Mock용어실제 객체를 대신하여 프로그래밍을 테스트할 수 있는 모의 객체를 생성하는 것으로 특정 동작이나 결과를 설정하고 검증하기 위해 사용됩니다.
Stub용어특정 메서드 호출에 대해 미리 정의된 동작을 반환하는 객체로, 테스트에서 사용될 때 실제 동작이 아닌 가짜 동작을 수행합니다.
Spy용어실제 객체를 사용하면서 해당 객체의 일부 동작을 감시하고 기록할 수 있는 객체입니다.
Mocking용어특정 동작이나 결과를 시뮬레이션하기 위해 모의 객체를 생성하거나 가짜 동작을 정의하는 것을 말합니다.
Verification용어메서드 호출이나 객체 동작이 예상대로 수행되었는지 확인하는 작업입니다.
Matchers메서드모킹이나 확인 작업에서 사용되는 매개변수 일치 여부를 확인하는 데 사용되는 메서드를 제공합니다.
MockitoAnnotations클래스Mockito 애너테이션을 사용하여 Mock 및 Spy 객체를 초기화하는 데 사용되는 클래스입니다.
MockitoJUnitRunner클래스JUnit 테스트에 Mockito를 사용하는 데 필요한 설정을 자동으로 처리하는 러너 클래스입니다.
MockitoJUnitRunner.Silent클래스MockitoJUnitRunner와 유사하지만, Mock 객체를 생성하지 않은 클래스에서도 실행할 수 있습니다.

[!note]
Spy

기존 객체의 일부 메서드를 원본 동작을 유지하면서 변경하거나 감시할 수 있게 해주는 기능을 제공한다.

Spy를 사용하면 실제 객체를 생성하고, 원하는 메서드를 호출할 수 있다.
이는 테스트 도중에 객체의 일부 동작을 감시하고, 특정 메서드 호출을 확인하거나 원하는 대로 메서드의 반환 값을 변경할 수 있는 유연성을 제공한다.

List<String> originalList = new ArrayList<>();

List<String> spyList = Mockito.spy(originalList);

Mockito.doReturn("Mocked").when(spyList).get(0);

String element = spyList.get(0); // "Mocked" 반환

Mockito 주요 어노테이션

Annotation설명
@Mock- 모의 객체(Mock Object)를 생성하는데 사용됩니다.
@Spy- 스파이 객체(Spy Object)를 생성하는데 사용됩니다.
@Captor- 모의 객체에 전달된 메서드 인수를 캡처하는데 사용됩니다.
@InjectMocks- 테스트 대상이 되는 객체에 ‘모의 객체를 자동으로 주입’할때 사용이 됩니다.
@MockBean- 스프링 프레임워크에서 사용되며, 테스트용 Mock 객체를 생성하고 주입하는 데 사용됩니다.
@MockitoSettings- Mockito의 설정을 변경하거나 커스터마이징 할 때 사용됩니다.
@MockitoJUnitRunner- JUnit 테스트에서 Mockito를 사용하기 위해 실행할 때 사용됩니다.
@BDDMockito- BDD 스타일의 테스트를 위해 Mockito를 사용할 때 사용됩니다.
  • @InjectMocks, @Mock는 Mockito에서 유닛 테스트에 사용 되고 @MockBean은 Spring Boot에서 통합 테스트에서 사용 된다. @Mock은 특정 클래스나 인터페이스에 대해 모의 객체를 생성하는 역할을 수행한다.
  • @InjectMocks는 테스트 대상 객체에 모의 객체를 주입하는 역할을 수행한다.
  • @Mock 어노테이션을 사용해서 Mockito.mock()을 대체하는 경우
    - @ExtendWith(MockitoExtension.class 어노테이션을 사용해야 테스트 시작 전 어노테이션을 감지하여 Mock 객체를 주입하기 때문에 꼭 같이 사용해야한다.

[!caution]
모의 객체 생성과 모의 객체 주입

@Mock과 같이 모의 객체를 생성한다는 것은 실제 객체와 동일한 메서드와 동작을 가지지만 실제 데이터나 외부 리소스와의 상호작용은 없다.
@InjectMocks와 같이 모의 객체를 주입한다는 것은 테스트의 대상이 특정 모의 객체를 사용해야 할 때, 그 모의 객체를 자동으로 주입하여 테스트를 수행할 수 있도록 한다.
모의 객체를 주입하는 경우 @Mock, @Spy등으로 생성한 모의 객체가 자동으로 주입되어 테스트를 진행한다.

Mockito 주요 메서드

Mockito 객체가 가지는 주요 메서드

메서드설명
mock(Class class)- 주어진 클래스의 모의 객체를 생성합니다.
doReturn(T value)- 모의 객체의 특정 메서드 호출에 대한 반환 값을 정의합니다.
when(T methodCall)- 주어진 메서드 호출에 대한 스텁(stub)을 정의하여 예상동작을 정의하거나 검증할 수 있도록 합니다.
thenReturn(T value)- when() 메서드와 함께 사용하여 특정 메서드 호출에 대한 반환 값을 지정합니다.
given(T methodCall)- 모의 객체의 메서드 호출 동작을 정의합니다. when() 메서드와 동일한 역할을 합니다
verify(T mock)- 주어진 모의 객체에 대한 메서드 호출 검증을 수행합니다.
any(Class clazz)- 주어진 클래스에 대해 임의의 인스턴스를 나타내는 Matcher를 생성합니다.
eq(T value)- 주어진 값을 기준으로 매처(matcher)를 생성합니다.
- value에는 null이나 원시 타입의 값 또는 객체가 포함될 수 있습니다.
verifyNoMoreInteractions(T... mocks)- 주어진 모의 객체들에 대한 추가적인 상호작용이 없는지 검증합니다.
- mocks에는 검증할 모의 객체들의 목록을 전달합니다.

Spring Boot 테스트

@SpringBootTest 어노테이션을 활용한 테스트로, 어플리케이션 컨텍스트를 로딩하고 Bean을 초기화하는 등 테스트에 필요한 설정과 의존성을 설정하는데 도움을 준다.

애플리케이션의 다양한 컴포넌트를 테스트할 수 있으며, 외부 서비스와의 상호작용, 데이터베이스 연동 등을 포함한 실제 환경에서의 동작을 확인할 수 있다.

@Autowired의 대체

@SpringBootTest에선 @Autowired 어노테이션으로 컨텍스트에서 알아서 생성된 객체를 주입받아 테스트를 진행할 수 있도록 했다.

다만 이 경우 문제가 있는데, DB Connection 등 여러 자원을 설정해야 하는 복잡성과 모든 외부 의존성을 실제로 설정하고 연결해야 하는 통합 테스트의 비효율성을 가진다. 실제 테스트가 진행될 단위의 관심사 영역 밖의 요소까지 고려해야 한다.

org.springframework.boot.test 패키지에서는 이를 고려한 어노테이션을 가지고 있다.

@MockBean

@Mock과 비슷한 이름인 @MockBean 어노테이션은 실제로도 비슷하게 동작하며, 단순히 객체를 모방하는 것이 아니라 Spring 컨텍스트에 해당 Mock 객체를 Bean으로 등록한다.

따라서 @Autowired가 동작할 때 등록되어있는 Mock 객체들을 사용할 수 있도록 동작한다.

@MockBean
private SomeRepository someRepository;

@MockBean
private SomeComponent someComponent;

@Autowired
private SomeService someService;

위와 같은 경우 SomeService가 SomeComponent와 SomeRepository의 Mock 객체와 자동으로 와이어링된다(각각의 Mock 객체가 Bean으로 등록되었기 때문.)

@MockBean과 @InjectMocks
Mock 종류의존성 주입 Target
@Mock@InjectMocks
@MockBean@SpringBootTest

@Mock은 @InjectMocks에 대해서만 해당 클래스안에서 정의된 객체를 찾아서 의존성을 해결한다.

@MockBean은 mock 객체를 스프링 컨텍스트에 등록하는 것이기 때문에 @SpringBootTest를 통해서 Autowired에 의존성이 주입된다.

@SpyBean

@MockBean에서 Spy로 개념만 변경된 어노테이션이 @SpyBean이다.
Stub 된 메서드 이외에 Spy 대상 객체의 실제 메서드도 실행이 가능하다.

[!caution]
@SpyBean이 Interface일 경우에는 해당 Interface를 구현하는 실제 구현체가 반드시 스프링 컨텍스트에 등록되어 있어야 한다.

MockMvc

스프링 프레임워크에서 제공하는 웹 애플리케이션 테스트용 라이브러리를 의미한다. HTTP 요청을 작성하고 컨트롤러의 응답을 검증하는 등 통합 테스트를 실행하지 않고도 컨트롤러의 동작을 확인할 수 있다.

컨트롤러의 엔드포인트를 호출하여 HTTP 클라이언트의 요청을 모방하고 적절한 응답을 확인하기 위해 테스트를 수행한다.

이러한 테스트 과정을 통해 애플리케이션의 서비스 로직이나 API 엔드포인트가 의도한 대로 동작하는지 확인하고, 버그를 발견하고 수정하는 데 도움을 준다.

MockMvc의 흐름

  1. TestCase -> MockMvc : 테스트 케이스 내에서 MockMvc 객체를 생성한다. 이 객체는 테스트할 컨트롤러와 상호작용을 하는데에 사용된다.
  2. MockMvc -> TestDispatcherServlet : MockMvc를 사용하여 원하는 엔드포인트에 요청을 보낸다. 또한 해당 요청에 필요한 파라미터, 헤더 또는 쿠키 등을 설정한다.
  3. TestDispatcherServlet -> Controller : 요청을 실행하고 응답을 받아 andExpect()를 사용하여 응답의 상태 코드, 헤더, 본문 등을 검증할 수 있다.

MockMvc, ResultActions, MvcResult의 주요 메서드

MockMvc

Spring Docs - MockMvc

메서드설명
standaloneSetup()특정 컨트롤러를 MockMvc에 설정하여 테스트할 수 있는 환경을 구성합니다.
perform()MockMvc를 사용하여 HTTP 요청을 실행합니다.
andExpect()컨트롤러의 응답을 검증합니다.
andExpect(status().isOk())응답 상태 코드가 200인지 확인합니다.
andExpect(content().string("expected"))응답 본문의 내용이 "expected"인지 확인합니다.
andExpect(jsonPath("$.property").value("expected"))JSON 응답에서 특정 속성의 값이 "expected"인지 확인합니다.
andExpect(view().name("expectedView"))응답에 대한 뷰의 이름이 "expectedView"인지 확인합니다.
andExpect(model().attribute("attributeName", "expectedValue"))모델 속성의 값이 "expectedValue"인지 확인합니다.
andExpect(redirectedUrl("expectedUrl"))리다이렉트된 URL이 "expectedUrl"인지 확인합니다.

ResultActions

MockMvc를 사용하여 실행한 HTTP 요청에 대한 결과를 나타낸다. 이를 통해 컨트롤러의 응답을 검증하고 원하는 동작을 수행할 수 있다.

Spring Docs - ResultActions

메서드설명
andReturn()해결된 MvcResult 객체를 반환합니다.
andReturn(MvcResult)반환할 MvcResult를 설정합니다.
andDo(ResultHandler)결과에 대해 추가 작업을 수행합니다.
andDo(ResultMatcher)결과에 ResultMatcher를 추가합니다.
andExpect(ResultMatcher)결과에 대한 기대치로 ResultMatcher를 추가합니다.
andForward()요청을 다음 핸들러로 전달합니다.
andForward(String)요청을 지정된 URL로 전달합니다.
andExpect(MockMvcResultMatchers)MockMvcResultMatchers에서 ResultMatcher를 추가합니다.
andExpect(MockMvcResultHandlers)MockMvcResultHandlers에서 ResultHandler를 추가합니다.
andReverse()이전 전달을 뒤집습니다.
andForwardDefault()요청을 기본 핸들러로 전달합니다.
andForwardDefault(String)요청을 지정된 URL로 기본 핸들러로 전달합니다.
andReturnDefault()기본 핸들러에 대한 해결된 MvcResult 객체를 반환합니다.
andReturnDefault(MvcResult)기본 핸들러에 반환할 MvcResult를 설정합니다.
andDoDefault()기본 핸들러에 대해 추가 작업을 수행합니다.
andDoDefault(ResultHandler)지정된 핸들러를 사용하여 기본 핸들러에 대해 추가 작업을 수행합니다.
andDoDefault(ResultMatcher)기본 핸들러에 ResultMatcher를 추가합니다.
andExpectDefault(ResultMatcher)기본 핸들러에 대한 결과 기대치로 ResultMatcher를 추가합니다.
andForwardNamed(String)지정된 URL로 명명된 핸들러로 요청을 전달합니다.
andReturnNamed(String)명명된 핸들러에 대한 해결된 MvcResult 객체를 반환합니다.
andDoNamed(String)명명된 핸들러에서 추가 작업을 수행합니다.
andDoNamed(String, ResultHandler)지정된 핸들러를 사용하여 명명된 핸들러에서 추가 작업을 수행합니다.
andDoNamed(String, ResultMatcher)명명된 핸들러에 ResultMatcher를 추가합니다.
andExpectNamed(String, ResultMatcher)명명된 핸들러에 대한 결과 기대치로 ResultMatcher를 추가합니다.
andReverseNamed(String)이전 명명된 핸들러로의 전달을 뒤집습니다.
andReverseDefault()기본 핸들러로의 이전 전달을 뒤집습니다.

MvcResult

MockMvc에서 수행된 MVC 요청의 결과에 대해 상세정보를 제공한다. 이 클래스는 응답 상태, 헤더, 내용 등과 같은 정보를 추출하기 위한 다양한 메서드를 포함하고 있다.

Spring Docs - MvcResult

메서드설명
getModelAndView()응답에 대한 모델과 뷰를 담고 있는 ModelAndView 객체를 반환합니다.
getRequest()응답과 관련된 HttpServletRequest 객체를 반환합니다.
getResponse()응답과 관련된 HttpServletResponse 객체를 반환합니다.
getResponseHeaders()응답 헤더를 맵 형태로 반환합니다.
getResponseStatus()응답 상태 코드를 반환합니다.
getModel()응답으로부터 모델 객체를 반환합니다.
getModelAndViewName()ModelAndView 객체로부터 뷰의 이름을 반환합니다.

그 외 MockMvc에서 사용되는 어노테이션들

어노테이션설명
@ExtendWith(MockitoExtension.class)Mockito를 사용하여 모킹하기 위해 테스트 클래스에 적용됩니다.
@WebMvcTest웹 MVC 테스트를 위해 스프링 컨텍스트를 구성합니다.
@AutoConfigureJsonTestersJSON 테스트를 위해 JsonTester의 자동 구성을 활성화합니다.
@AutoConfigureMockMvcMockMvc를 자동으로 구성하는 데 사용됩니다.

참조

Contributor9 - SpringBoot Mockito 이해하기
https://cobbybb.tistory.com/16

profile
Bad Language

0개의 댓글

관련 채용 정보