[컴][파이썬] Mock 사용하기


unit test mock up / unittest mock / mock 사용하기 / 파이썬에서 mock 사용하기



Mock module

python 에서 mock 을 사용해 보자.
ref. 1 에서 stub/fake 와 mock 을 따로 구분하고 있는데, 사실 전부 가상의 object 라고 할 수 있는데, mock 을 좀 더 기능이 많은 녀석으로 분류하고 있다.

mock 은 method 가 특정 input 을 넣었을 때 특정 output 이 나오는가를 검증하는 것(state verification) 에 더해서, method 가 특정 method 를 몇 번 호출해야 하고 등등의 method 의 동작을 검증하는  것(behavior verification) 도 가능하게 해 주는 것이라고 이야기 한다.
  • state verification
  • behavior verification

python 3.0 에서는 표준 module 로 포함되어 있지만, python 2.x 버전(2.4 ~2.7) 에서는 따로 download 받아서 사용해야 한다.[ref. 1] download 는 아래 경로에서 받을 수 있다.

python 3.3 에서 부터 unittest mock up 이 standard library 에 추가됐다. 사용법은 어렵지 않다. 아래 글을 참고하자.

유용한 함수들

  • MagicMock : mockfunc = MagicMock(return_value=3) 으로 mockfunc() 을 호출하면 무조건 return 값이 3으로 나오게 할 수 있다.
  • assert_called_with  : assert_called_with 로 함수가 호출될때 어떤 parameter 를 받는지에 대한 test 를 할 수 있다.
  • assert_has_calls : 함수가 어떤 parameter 를 가지고 호출이 되는지를 test할 수 있다.


import unittest
from unittest.mock import MagicMock
from unittest.mock import ANY, call

import myproj.FileMailer

class TestFileMailer(unittest.TestCase):

    def setUp(self):
        
        self.fmailer = FileMailer(os.path.abspath(__file__))
        self.fmailer.sendThruSendMail = MagicMock(return_value=3)
        # mock
        self.fmailerMock = Mock()
        self.fmailerMock.getTargetList = MagicMock(return_value=[{'user_id': 1}])

   def test_send(self):
        htmlMessage = '<html></html>'
        subj = 'test1'
        expSubj = "[새로운] 'test1' 의 메일제목."
        
        self.fmailer.send(
            'ga@gamil.com',
            info={'title': subj}
        )
        self.fmailer.sendThruSendMail.assert_called_with(ANY, expSubj, 'my-test')

    def test_send2(self):
        self.fmailer.send(
            'ga@gamil.com',
            info={'title': subj}
        )
        self.fmailer.sendThruSendMail.assert_has_calls(
            [call('ga@gamil.com', info={'title': subj}), 
             call('ga@gamil.com', info={'title': subj})])

    def test_send3(self):
        fm = self.fmailerMock()
        tlist = fm.getTargetList()
        for t in tlist:
            self.assertEqueal(1, t.user_id, 'user_id check')


request test

request 를 mock 으로 돌리고, request 로 넘어오는 parameter 를 점검한다.

만약 일부 parameter 를 다른 곳에서 test 한다면, 그 parameter 에 대해서 ANY 를 사용하면 된다.

class CumaTask(object):
    
    def __init__(self, channel):
        super().__init__()
        self.channel = channel

    def transfer(self, session, pid):
        infoMgr = InfoManager(session)
        info = infoMgr.getInfo(pid)

        ch = self.channel
        for row in info:
            res = ch.request(apiName=MyNetApi.TRANSFER, data=row)

        return

class TestMyNet(unittest.TestCase):
    maxDiff = None 
    def setUp(self):
        pass

    def testMyNetTask(self):
        
        pid = self.pid
        
        ch = MyNetChannel()
        ch.request = MagicMock(return_value={})

        ctask = MyNetTask(ch)
        ctask.transfer(self.session, pid)
        ch.request.assert_has_calls([call(apiName=MyNetApi.TRANSFER, data=ANY)])

See Also

  1. 쿠...sal: [컴][자바] Mockito 사용법 - Unit test Mock up
  2. 쿠...sal: [컴][파이썬] vscode 에서 파이썬 유닛테스트 설정

References

  1. Using Mocks in Python | Dr Dobb's

댓글 없음:

댓글 쓰기