fromunittest.mockimportpatchdeftest_something():withpatch('module.function')asmock_func:mock_func.return_value='mocked'# 테스트 코드result=module.function()assertresult=='mocked'# with 블록 밖에서는 원래 함수 복원
fromunittest.mockimportMock,MagicMock# Mock은 매직 메서드 자동 지원 안 함mock=Mock()# len(mock) # TypeError# MagicMock은 지원magic=MagicMock()magic.__len__.return_value=5print(len(magic))# 5# 컨텍스트 매니저로 사용magic.__enter__.return_value='entered'withmagicasm:print(m)# 'entered'
8. spec - 인터페이스 제한
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fromunittest.mockimportMockclassDatabase:defconnect(self):passdefquery(self,sql):pass# spec 없이: 아무 메서드나 호출 가능 (오타 감지 불가)mock=Mock()mock.conect()# 오타지만 에러 없음# spec 있으면: 실제 클래스 인터페이스만 허용mock=Mock(spec=Database)# mock.conect() # AttributeError: Mock has no attribute 'conect'mock.connect()# OK
9. autospec - 시그니처 검증
1
2
3
4
5
6
7
8
9
10
fromunittest.mockimportcreate_autospecdefadd(a,b):returna+b# autospec: 시그니처도 검증mock_add=create_autospec(add)mock_add(1,2)# OK# mock_add(1) # TypeError: missing argument 'b'# mock_add(1, 2, 3) # TypeError: too many arguments
fromunittest.mockimportMock,patch# 테스트 대상 코드classUserService:def__init__(self,db,email_client):self.db=dbself.email_client=email_clientdefcreate_user(self,name,email):user_id=self.db.insert('users',{'name':name,'email':email})self.email_client.send_welcome(email)returnuser_id# 테스트deftest_create_user():# 의존성 모킹mock_db=Mock()mock_db.insert.return_value=123mock_email=Mock()# 테스트service=UserService(mock_db,mock_email)result=service.create_user('Alice','alice@example.com')# 검증assertresult==123mock_db.insert.assert_called_once_with('users',{'name':'Alice','email':'alice@example.com'})mock_email.send_welcome.assert_called_once_with('alice@example.com')
11. patch.dict - 딕셔너리 패치
1
2
3
4
5
6
7
8
fromunittest.mockimportpatchimportos# 환경 변수 패치withpatch.dict(os.environ,{'API_KEY':'test_key'}):print(os.environ['API_KEY'])# 'test_key'# 블록 밖에서는 원래 값