Mock

Heath_Jeong·2021년 3월 4일
0

Mock 이란?

mock 의 원래 뜻은 모조품, 모조 객체이다. 유닛 테스트를 수행할 때 단순히 맞고 틀린지 등을 비교하는 assert 계열의 함수만으로 테스트가 충분하지 않을 때가 있다. 테스트를 위해 외부 API, 네트워킹이나 db 사용 등의 환경이 필요할 때, mock 이 이들을 대신하여 테스트 환경을 지원한다. 즉, mock 은 테스트에 필요한 외부 환경에 의존하지 않고 독립적으로 테스트를 수행할 수 있게 해주는 기특한 툴이다.

mock 객체는 return_valueside_effect 옵션을 가진다. 객체를 생성할 때 지정해줘도 되고 객체 생성 후에 직접적으로 옵션을 설정해줘도 무방하다.

Mock 객체 기본 생성

return_value 옵션은 생성된 mock 객체를 호출했을 때 값을 설정할 수 있다.

  from unittest.mock import Mock

  my_mock = Mock(return_value = "I'm mock.")
  print(my_mock)
  # I'm mock.
  my_mock.return_value = "Neck slice")
  print(my_mock)
  # Neck slice

side_effect 옵션은 mock 객체를 호출할 때 지정한 익셉션을 호출 할 수도 있고, 아니면 호출할 때마다 iteratornext 함수처럼 값을 하나씩 호출하도록 설정할 수도 있다.

  from unittest.mock import Mock

  # 익셉션 호출
  my_mock = Mock(side_effect = Exception("Mock Error"))
  print(my_mock)
  # Exception: Mock Error 익셉션 발생

  # 값 한개씩 호출
  my_mock = Mock(side_effect = [1, 2, 3])
  print(my_mock)
  # 1
  print(my_mock)
  # 2
  print(my_mock)
  # 3
  print(my_mock)
  # StopIteration 익셉션 호출

Mock 객체 내장함수

함수이름기능
call_args마지막으로 설정한 arguments 리턴
call_count몇 번 호출되었는지 리턴
assert_called한 번도 호출되지 않았으면 익셉션 발생, 호출된 적 있으면 통과
assert_called_once딱 한 번만 호출 되었으면 통과
assert_not_called한 번도 호출되지 않았으면 통과

patch 함수

mock 객체는 보통 위에 적힌 기본 생성 방법으로 생성하지 않고, 내장함수 표에서 언급하지 않은 내장함수 patch 를 사용하여 외부 API 에 독립적인 객체를 생성해낸다. patch 로 객체를 만드는 방법에는 decorator 를 사용하거나 with 를 사용하는 방법이 있다.

어떤 모듈이 사용자로부터 소문자 영어 알파벳을 입력받아 대문자로 프린트해준다고 가정하자. 그리고 사용자로부터 0을 입력받으면 종료 멘트와 함께 프로그램이 종료된다. 이 모듈을 테스트하는 코드에서 여러 인풋값 (상황) 을 설정해두고 그 결과를 플로우대로 검사하고 싶을 때 mock 을 사용하면 유용하다.

test_module.py

  import unittest
  from unittest.mock import patch
  import module

  class TestModule(unittest.TestCase):
    def test_main(self):
      # 입력은 반드시 영어 소문자나 0만 들어옴을 보장
      input_list = ['a', 'd', 0]

      # with 를 사용한 mock 객체 생성
      with patch('builtins.input', side_effect=input_list):
        with patch('sys.stdout', new=StringIO()) as fakeOutput:
          module.main()
          console = fakeOutput.getvalue().strip().split("\n")
          self.assertIn("A", console[0].upper())
          self.assertIn("D", console[1].upper())
          self.assertIn("BYE", console[2].upper())

결론

mock 은 유닛 테스트에서 외부 환경에 대한 의존성을 없애고 독립적으로 테스트를 수행할 수 있게 외부 환경 객체 역할을 대신해준다. mockpatch 를 이용해 decorator 또는 with 구문으로 생성하여 사용한다.

profile
데이터로 문제를 해결하는 엔지니어를 꿈꿉니다.

0개의 댓글