모킹이란
모킹(mocking)은 외부 서비스에 의존하지 않고 독립적으로 실행이 가능한 단위 테스트를 작성하기 위해서 사용되는 테스팅 기법이다. 단위 테스트를 작성할 때 외부에 의존하는 부분을 임의의 가짜로 대체하는 기법이 자주 사용되는데 이를 모킹(mocking)이라고 한다.
unittest.mock 모듈의 patch() 데코레이터
Mock 객체 설정하기
mocking은 mock이라고 불리는 가짜 객체를 생성하는 것부터 시작한다.
이 mock 객체가 어떻게 작동을 할지를 지정해줄 수 있으며, 이 mock 객체는 자신을 상대로 어떤 작업이 일어났는지를 기억한다.
먼저 호출되었을 때 특정 값을 리턴하는 mock 객체는 return_value 옵션을 이용해서 생성할 수 있다.
>>> from unittest.mock import Mock
>>> mock = Mock(return_value='Hello, Mock!')
>>> mock()
'Hello, Mock!'
반면에 호출되었을 때 예외가 발생하는 mock 객체는 side_effect 옵션을 이용해서 생성할 수 있다.
>>> mock = Mock(side_effect=Exception('Oops!'))
>>> mock()
Traceback (most recent call last):
~~
Exception: Oops!
side_effect 옵션에 리스트를 넘기면 mock 객체가 호출될 때 마다 매 번 다른 값을 리턴할 수도 있다.
>>> mock = Mock(side_effect=[1, 2, 3])
>>> mock()
1
>>> mock()
2
>>> mock()
3
>>> mock()
Traceback (most recent call last):
~~
StopIteration
side_effect 옵션에 함수를 넘기면 mock 객체를 호출했을 때 주어진 인자에 따라 다른 값을 리턴할 수 있다.
>>> mock = Mock(side_effect=lambda x: x * 10)
>>> mock(1)
10
>>> mock(2)
20
return_value와 side_effect 옵션은 꼭 Mock() 생성자의 인자로 넘어갈 필요는 없습니다. 다음과 같이 mock 생성 이후에도 얼마든지 이 옵션 값은 바꿀 수가 있다.
>>> mock = Mock()
>>> mock.return_value = 1
>>> mock()
1
>>> mock.return_value = 2
>>> mock()
2
mock 객체의 속성이나 메서드도 또 다른 mock 객체가 된다.
>>> mock = Mock()
>>> mock.attribute = 'ATTRIBUTE'
>>> mock.attribute
'ATTRIBUTE'
>>> mock.method.return_value = 'METHOD RETURN VALUE'
>>> mock.method()
'METHOD RETURN VALUE'
assert_called_once() 메서드는 해당 mock이 단 한 번 호출되었는지 검증할 때 쓰입니다.
>>> mock = Mock()
>>> mock()
<Mock name='mock()' id='4559483280'>
>>> mock.assert_called_once()
>>> mock()
<Mock name='mock()' id='4559483280'>
>>> mock.assert_called_once()
Traceback (most recent call last):
~~
AssertionError: Expected 'mock' to have been called once. Called 2 times.
assert_called_with() 메서드를 사용하면 해당 mock이 호출되었을 때 어떤 인자가 넘어왔는지까지도 검증할 수 있다.
>>> mock = Mock()
>>> mock('A', B='C')
<Mock name='mock()' id='4559461968'>
>>> mock.assert_called_with('A', B='C')
patch 데코레이터
unittest.mock 모듈의 patch() 데코레이터는 특정 범위 내에서만 mocking이 가능하도록 해준다. 일반적으로 다음과 같이 patching이 필요한 단위 테스트 메서드에 patch() 데코레이터를 선언해줌으로써 해당 메서드 내에서만 patching이 이뤄지게 한다.
MagicMock
기본적으로 Mock 클래스를 사용하면 이러한 매직 메서드가 자동으로 모킹되지 않는다.
>>> from unittest.mock import Mock
>>> mock = Mock()
>>> mock.__str__.return_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method-wrapper' object has no attribute 'return_value'
매직 메서드를 모킹하려면 다른 속성이나 메서드와 달리 다음과 같이 새로운 mock 객체를 직접 생성해서 할당을 해줘야 하는 불편함이 있다.
>>> mock.__str__ = Mock(return_value = "I'm a mock.")
>>> str(mock)
"I'm a mock."
하지만 Mock 클래스의 확장 버전인 MagicMock 클래스를 사용하면 이러한 매직 메서드를 미리 알아서 모킹을 해놓기 때문에 편리하다.
>>> from unittest.mock import MagicMock
>>> mock = MagicMock()
>>> mock.__str__.return_value
"<MagicMock id='4556752144'>"
>>> mock.__str__.return_value = "I'm a magic mock."
>>> str(mock)
"I'm a magic mock."
원문
'AI&ML > Lab' 카테고리의 다른 글
Triplet Loss (0) | 2025.03.04 |
---|---|
차원의 저주 (curse of dimensionality) (0) | 2024.12.24 |
[Debug] 디버깅하느라 print해놨는데 어디에 해놓았는지 모르는 경우 (0) | 2024.07.21 |
[Train] ControlNet 학습시키기 (3) | 2024.07.15 |
[ML/DL] 소프트맥스 회귀/다항 로지스틱 회귀 (0) | 2023.12.26 |
댓글