Backend/Test

[Mock] Mock, 도대체 뭐야? (Feat. 테스트코드)

Emil :) 2023. 11. 1. 22:59
728x90
반응형
이 글은 Notion에서 작성 후 재편집한 포스트입니다.


서론


프로젝트를 진행하며 본격적으로 테스트코드를 작성하기 시작했다.

강의를 보면서 대부분의 강의에서 모킹(Mocking)을 활용한 테스트코드 작성을 하던데, 아무리 봐도 DB 커넥션이 없는것이다.
내가 생각한 테스트코드는 DB에 직접 CRUD 작업을 거쳐서 하는것으로 알고있었는데... 그게 아니었다.

본 포스팅에선 테스트코드의 목적과, 가상 맵핑을 도와주는 Mock 프레임워크에 대해 알아보도록 하자.

참고


https://happy-coding-day.tistory.com/entry/Mock-%EA%B0%9D%EC%B2%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C-%EC%99%9C-%EC%8D%A8%EC%95%BC%EB%90%A0%EA%B9%8C

 

Mock 객체란 무엇일까? 왜 써야될까?

아래 내용은 위 책에서 말하는 4장 TDD with Mock 에서 내용을 발췌했습니다. TDD를 공부하면서 Mock 이라는 용어는 너무나도 많이 나오고, 실제로 테스트 프레임워크를 사용하면 Mock 객체를 많이 사용

happy-coding-day.tistory.com

https://www.incodom.kr/Mock

 

생물정보 전문위키, 인코덤

Wikipedia for Bioinformatics

www.incodom.kr

본론


테스트코드면 DB까지 다 테스트 해봐야되는거 아냐?


결론부터 말하자면, "반은 맞고 반은 틀리다" 이다.

개발을 진행하다보면, 실제 객체를 생성해서 테스트하기엔 너무 의존성이 깊거나, 볼륨이 크거나, 실제 객체를 만들 필요가 없는 케이스가 더러 있다.

그렇다면 실제 객체를 생성하지 않거나, DB 커넥션 레벨까지 가지 않고 애플리케이션 레벨에서 테스트가 필요하다면, DB 커넥션이 이루어졌다고 상정하고 테스트를 진행해야 할텐데, 어떻게 해야될까?

이럴 때 필요한 것이 바로 Mock 이다.

테스트는 크게 세가지로 나뉜다.

  1. 단위 테스트 : 기능 혹은 함수별로 테스트를 진행 ex) 글 작성
  2. 통합 테스트 : 단위 테스트들이 모여서 하나의 큰 작업이 정상적으로 이루어지는지 확인하는 테스트 ex) 글 작성, 조회, 수정, 삭제
  3. E2E 테스트 : A부터 Z까지 일련의 과정을 모두 테스트 ex) 회원가입 - 로그인 - 게시판 조회 - 글 작성 ...

Mock은 앞서 말한 테스트의 경중이 낮을 때, 즉 단위테스트에서 자주 사용된다.
따라서 단위테스트의 경우엔 DB커넥션까지 가지 않고, 통합테스트부터 커넥션이 이어진다.

그래서 Mock이 뭔데?


Mock은 앞서 말한것처럼 실제로 DB에 연결을 수행하지 않고, 가짜 객체(Fake Object)를 생성해낸다.
이렇게 생성된 가짜 객체를 통해 전반적인 테스트를 수행하게 된다.
즉, Mock은 가짜 객체를 통칭하는 큰 의미의 개념이고, 프레임워크는 여러가지 있다.

Mock에 대한 이해도를 높이려면 다음과 같은 용어의 이해가 필요하다.

용어만 봐선 이해가 되지 않으니, 코드를 꼭 참고하며 이해도를 높여보자.

 

  • 테스트 더블
    테스트를 진행하기 어려운 경우, 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체.
    Mock 객체와 유사한 의미지만, 테스트 더블이 좀 더 상위 의미. 후술할 내용들을 통칭하는 개념.
  • 더미 객체(Dummy Object)
    페이크 객체와는 다르다. 객체의 껍데기만 구현하고 내부 기능이나 로직은 필요없을 때 사용된다.
public class DummyCalculator implements Calculator {
    @Override
    public int add(int a, int b) {
        return 0; // 아무 동작도 하지 않음
    }
}
  • 테스트 스텁(Test Stub)
    더미 객체보다 좀 더 디테일한 객체다. 뭔가 동작을 하는것처럼 만들어놓은 객체다.
    특정 상태를 가정해서 하드코딩된 형태이므로, 로직에 따른 값에 대한 변경은 체크할 수 없다.
public class TestStubCalculator implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b + 10; // 기존 동작 대신 10을 더함
    }
}
  • 페이크 객체(Fake Object)
    말 그대로 가짜 객체이다. 실제로 로직이 구현된것처럼 보이게 한다.
    실제로 db에서 값을 가져온 것처럼 객체 내부에 구현이 가능하며, 이에 대한 구현이 복잡한 경우 Mock 프레임워크를 사용하기도 한다.
public class FakeDatabase implements Database {
    private Map<String, String> data = new HashMap<>();

    @Override
    public String readData(String key) {
        return data.get(key);
    }

    @Override
    public void writeData(String key, String value) {
        data.put(key, value);
    }
}
  • 테스트 스파이(Test Spy)
    테스트에 사용되는 객체이다. 메소드의 사용 및 정상호출 여부를 기록하고 호출 시 알려준다.
    테스트 더블로 구현된 객체에 자기 자신이 호출되었을 때 확인이 필요한 부분을 기록하도록 구현한다.
    아주 특이한 케이스 이외엔 그냥 Mock에서 제공하는 기본적인 기능들로 커버가 가능하다.
public class TestSpyLogger implements Logger {
    private int logCount = 0;

    @Override
    public void log(String message) {
        logCount++;
        // 로그 메시지 수집 또는 확인 로직
    }

    public int getLogCount() {
        return logCount;
    }
}
  • Mock 객체(Mock Object)
    지금까지 계속 말한 Mock 객체이다. 즉, 행위를 검증하기 위해 사용되는 객체.
    대표적인 프레임워크는 Mockito(최근 가장 핫함), EasyMock, JMock 등이 있다.
    아래는 Mockito 예제다.
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;

public class ExampleTest {

    @Test
    public void testMockObject() {
        // Mock 객체 생성
        Calculator calculator = mock(Calculator.class);

        // Mock 객체에 대한 동작 설정
        when(calculator.add(2, 3)).thenReturn(5);

        // 테스트 대상 객체 (예: CalculatorUser) 생성
        CalculatorUser calculatorUser = new CalculatorUser(calculator);

        // 테스트 대상 메서드 호출
        int result = calculatorUser.addNumbers(2, 3);

        // Mock 객체에 대한 동작 확인
        verify(calculator).add(2, 3); // add 메서드가 2와 3 인자로 호출되었는지 확인
        verifyNoMoreInteractions(calculator); // 더 이상 호출되지 않았는지 확인

        // 결과 검증
        assertEquals(5, result);
    }
}

Mock 자체가 프레임워크라고 생각했는데 그건 아니고, 개념의 일종이다. (객체, 클래스 뭐 이런 '개념' 말이다.)

결론


본 포스팅에선 단위테스트에 자주 사용되는 Mock과 관련 프레임워크에 대해 짤막하게 알아봤다.

통합테스트에선 추가적으로 DB커넥션이 필요하다.
이 작업을 위해선 @SpringBootTest 와 @DataJpaTest 라는 어노테이션이 필요한데, 이 부분은 현재 에러가 나고 있어서.. 열심히 알아보고 수정중이다 ㅠㅠ

해당 문제가 해결되는 대로 포스팅을 작성해보도록 하겠다.

구독 및 하트는 정보 포스팅 제작에 큰 힘이됩니다♡

728x90
반응형