일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 개발자
- can
- 암호화폐
- 클라우드
- 퀀트
- 확률
- 오토사
- 파이썬
- TOEFL
- 블록체인
- 자동차sw
- AWS
- 백트레이더
- toefl writing
- 토플
- python
- 아마존 웹 서비스
- backtrader
- Cloud
- 프로그래밍
- probability
- 자동매매
- GeorgiaTech
- 토플 라이팅
- Bitcoin
- 백테스트
- AUTOSAR
- it
- 비트코인
- backtest
- Today
- Total
Leo's Garage
smtm #3 - mock 본문
mock란 실제 테스트하기에는 비용이 크거나 혹은 테스트할 수 없는 상황에 마치 진짜인 것처럼 동작하게 하는 모조품을 이르는 말이다.
이전 포스트에서 smtm 코드의 테스트 코드 예제를 살펴보면서 REST API의 테스트 코드를 작성하였다.
여기에는 큰 문제가 하나 있는데 REST API는 결국 외부의 서버(업비트)에게 정보를 요청하고 받게 된다는 점이다.
만약에 테스트 환경에서 internet이 안되거나 혹은 업비트의 서버가 불안정해서 정확한 정보를 받을 수 없다면 테스트 자체를 신뢰할 수 없는 상황이 된다.
우리는 테스트 환경을 일정하게 만들 필요가 있다.
실험 시 외부 요인을 통제하지 못한다면 실험 자체가 무의미한 것과 마찬가지이기 때문이다.
이러한 환경을 통제하기 위해서 우리는 unittest 모듈 내에 mock 객체를 사용하고자 한다.
https://docs.python.org/ko/3/library/unittest.mock-examples.html
mock 객체에 대한 자세한 설명은 상기 링크에서 확인할 수 있다.
mock를 사용한 예제 테스트 코드를 살펴보자
@patch("requests.get")
def test_initialize_from_server_update_data_correctly_with_empty_data(self, mock_get):
ex = TddExercise()
dummy_response = MagicMock()
mock_get.return_value = dummy_response
ex.initialize_from_server()
self.assertEqual(len(ex.data), 0)
@patch("requests.get")
def test_initialize_from_server_update_data_correctly(self, mock_get):
ex = TddExercise()
dummy_response = MagicMock()
dummy_response.json.return_value = [{"market": "apple"}, {"market": "banana"}]
mock_get.return_value = dummy_response
ex.initialize_from_server()
self.assertEqual(len(ex.data), 2)
self.assertEqual(ex.data[0], {"market": "apple"})
self.assertEqual(ex.data[1], {"market": "banana"})
mock_get.assert_called_once_with(ex.URL, params=ANY)
self.assertEqual(mock_get.call_args[1]["params"]["count"], 100)
@patch("request.get")
이 표현은 데코레이터라고 하는데 위와 같이 표기하면 해당 함수 내에서 requests 모듈 대신 mock 객체를 사용할 수 있게 된다.
test_initialize_from_server_update_data_correctly_with_empty_data 함수를 호출해보자.
TddExercise() 객체를 생성하였다.
dummy_response를 생성하고 해당 값을 mock.get의 return value로 설정한다.
이렇게 하면 해당 함수 내에서 requests get을 호출하면 mock.get의 return value를 반환하게 된다.
ex 객체에서 initialize_from_server를 호출하였고, 그 아래 결과로 데이터가 0임을 확인한다.
dummy_response 자체가 데이터가 아무것도 없으므로 length가 0임은 자명하다는 걸 알 수 있다.
좀더 복잡한 테스트로는 test_initialize_from_server_update_data_corretly를 살펴보자.
여기서는 dummy_response에 임의의 데이터를 집어넣었다.
총 2개의 데이터를 집어넣었고, 각 데이터의 위치에 값이 정상적으로 들어와 있는지 확인한다.
다만, 이 방식은 requests.get의 응답을 통제할 수는 있지만, 실제 파라미터들이 제대로 들어갔는지를 확인하지는 않는다.
mock_get.assert_called_once_with(ex.URL, params=ANY)
self.assertEqual(mock_get.call_args[1]["params"]["count"], 100)
위의 코드를 살펴보자.
assert_called_once_with은 한 번만 호출되어야 하는데 이 때, ex.URL이 들어가야 한다.
이는 정해진 URL이 아니라 다른 URL로 호출될 수도 있음을 확인하는 것이다.
구조상 기존의 테스트 코드는 정해진 URL이 아닌 다른 URL이 들어가더라도 호출이 가능했다.
call_arg는 객체가 마지막으로 호출된 인자이다.
즉 count parameter가 100으로 호출되었는지를 확인하는 코드라고 볼 수 있다.
이 리뷰는 아래 책을 바탕으로 작성되었습니다.
http://www.yes24.com/Product/Goods/107635612
'Study > AutoTradingBot' 카테고리의 다른 글
smtm #2 - TDD 예시 (0) | 2023.01.15 |
---|---|
smtm #1 - TDD 맛보기 (0) | 2023.01.06 |