Python unittest模拟类实例变量

时间:2017-11-10 17:28:07

标签: python unit-testing flask mocking python-unittest

我试图用python unittest.mock测试我的代码。

实际上,我的测试方式很受这篇博文的启发: http://engineroom.trackmaven.com/blog/real-life-mocking/

以下是我想在其中模拟内容的模块的一部分:

class RestRequestManager:
    """
    A Context Manager for class RestRequest.
        This context manager is call using the "with" statement and
         take a RestRequest object as parameter.
        The point is to automate login and logout.
    """
    def __init__(self, restReq):
        self.restReq = restReq

    def __enter__(self):
        """ Enter : login() """
        self.restReq.login()
        return self.restReq

    def __exit__(self, type, value, traceback):
        """ Exit : logout() """
        self.restReq.logout()


class RestRequest(RestRequestBase):
    """ class RestRequest. """
    def __init__(self, username, password, url_rest_base, endpoint, method, *args,
                 payload=None, outfile=None, file_mod=None):
        super().__init__(username, password, url_rest_base, endpoint, method, *args)
        self.method = method
        self.payload = payload
        self.outfile = outfile
        self.file_mod = file_mod
        self.response = None

def get_response(self):
    return self.response

以下是使用此模块的Flask应用程序的一部分:

class CtrlmJobIdLogs(Resource):
    """ Control-M log on jobid """

    def get(self, jobid):
        """Get job's log."""
        rest_req = restRequest.RestRequest(USERNAME, PASSWORD, URL_REST_BASE, ENDPOINT_LOGS,
                                           'GET', jobid, payload=None, outfile=None,
                                           file_mod=None)

        with restRequest.RestRequestManager(rest_req) as req_man:
            req_man.perform()

        logging.debug('DEBUG>> : ctrlm_job --> {}'.format(jobid))
        return {jobid: req_man.get_response().json()}

这是我的测试:

class MockTests(unittest.TestCase):
    """ Test the rest module with mocks """
    ############################
    #### setup and teardown ####
    ############################

    def setUp(self):
        """ Executed prior to each test """
        app.config['TESTING'] = True
        app.config['WTF_CSRF_ENABLED'] = False
        app.config['DEBUG'] = False

        self.client = app.test_client()

    def tearDown(self):
        """ executed after each test """
        pass

    ###############
    #### tests ####
    ###############
    #@mock.patch('MonAPPflaskRest.flaskRest.restRequest.RestRequestManager')
    @mock.patch('MonAPPflaskRest.flaskRest.restRequest.RestRequest')
    def test_ctrlM_no_output(self,  mock_RestRequest):
        """ UAT 4 : ctrl-M job output is not found. """
        print("\n\n======================================")
        print("test_ctrlM_no_output")
        print("======================================")


        jobid_no_output = 'blabla:1epyx'
        message_noutput = 'Job CTRL-M {} not found'.format(jobid_no_output)
        expected_dict = { "blabla:1epyx": {"errors": [{ "message": "Request  rejected by Data Center CTM5319 OUTPUT DOES NOT EXIST FOR THIS JOB"}]} }

        # mock object :
        mock_response = mock.MagicMock()
        mock_response.json.return_value = expected_dict
        mock_response.status_code.return_value = 500

        # # the patched object returns values
        mock_RestRequest.response.return_value = mock_response
        #mock_RestRequest.return_value.response.return_value.json.return_value = expected_dict

        # REST url to test
        url = '/ctrlm/{}/output/'.format(jobid_no_output, follow_redirects=True)

        # call
        response_dict = self.client.get(url)
        # https://stackoverflow.com/questions/28882226/convert-test-client-data-to-json

        # assertions tests
        mock_RestRequest.assert_called()


if __name__ == "__main__":
    unittest.main()

Pytest ouptut是:

collected 1 item

tests\test_mock.py F

================================== FAILURES ===================================
_______________________ MockTests.test_ctrlM_no_output ________________________

self = <test_mock.MockTests testMethod=test_ctrlM_no_output>
mock_RestRequest = <MagicMock name='RestRequest' id='79830480'>

    @mock.patch('MonAPPflaskRest.flaskRest.restRequest.RestRequest')
    def test_ctrlM_no_output(self,  mock_RestRequest):
        """ UAT 4 : ctrl-M job output is not found. """
        print("\n\n======================================")
        print("test_ctrlM_no_output")
        print("======================================")



        jobid_no_output = 'blabla:1epyx'
        message_noutput = 'Job CTRL-M {} not found'.format(jobid_no_output)
        expected_dict = { "blabla:1epyx": {"errors": [{ "message": "Request  rejected by Data Center CTM5319 OUTPUT DOES NOT EXIST FOR THIS JOB"}]} }


        # mock object :
        mock_response = mock.MagicMock()
        mock_response.return_value.json = expected_dict
        mock_response.return_value.status_code = 500

        # # the patched object returns values
        # mock_RestRequest.get_response.return_value = mock_response

        mock_RestRequest.get_response.return_value.status_code.return_value = 500
        mock_RestRequest.get_response.return_value.json.return_value = expected_dict

        #mock_RestRequest.return_value.response.return_value.json.return_value = expected_dict
        print('$$$$$$$$$$$$$$$$$$$$$$$', mock_RestRequest.mock_calls)
        print('$$$$$$$$$$$$$$$$$$$$$$$', mock_RestRequest.get_response.return_value.status_code.return_value)



         # REST url to test
        url = '/ctrlm/{}/output/'.format(jobid_no_output, follow_redirects=True)

        # call
>       response_dict = self.client.get(url)

tests\test_mock.py:70:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\virtualenvs\tools\lib\site-packages\werkzeug\test.py:791: in get
    return self.open(*args, **kw)
..\..\virtualenvs\tools\lib\site-packages\flask\testing.py:127: in open
    follow_redirects=follow_redirects)
..\..\virtualenvs\tools\lib\site-packages\werkzeug\test.py:764: in open
    response = self.run_wsgi_app(environ, buffered=buffered)
..\..\virtualenvs\tools\lib\site-packages\werkzeug\test.py:677: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
..\..\virtualenvs\tools\lib\site-packages\werkzeug\test.py:884: in run_wsgi_app
    app_rv = app(environ, start_response)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1997: in __call__
    return self.wsgi_app(environ, start_response)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1985: in wsgi_app
    response = self.handle_exception(e)
..\..\virtualenvs\tools\lib\site-packages\flask_restful\__init__.py:273: in error_router
    return original_handler(e)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1540: in handle_exception
    reraise(exc_type, exc_value, tb)
..\..\virtualenvs\tools\lib\site-packages\flask\_compat.py:32: in reraise
    raise value.with_traceback(tb)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1982: in wsgi_app
    response = self.full_dispatch_request()
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1614: in full_dispatch_request
    rv = self.handle_user_exception(e)
..\..\virtualenvs\tools\lib\site-packages\flask_restful\__init__.py:273: in error_router
    return original_handler(e)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1517: in handle_user_exception
    reraise(exc_type, exc_value, tb)
..\..\virtualenvs\tools\lib\site-packages\flask\_compat.py:32: in reraise
    raise value.with_traceback(tb)
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1612: in full_dispatch_request
    rv = self.dispatch_request()
..\..\virtualenvs\tools\lib\site-packages\flask\app.py:1598: in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
..\..\virtualenvs\tools\lib\site-packages\flask_restful\__init__.py:484: in wrapper
    return self.make_response(data, code, headers=headers)
..\..\virtualenvs\tools\lib\site-packages\flask_restful\__init__.py:513: in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
..\..\virtualenvs\tools\lib\site-packages\flask_restful\representations\json.py:21: in output_json
    dumped = dumps(data, **settings) + "\n"
c:\users\x165896\appdata\local\programs\python\python36-32\Lib\json\__init__.py:231: in dumps
    return _default_encoder.encode(obj)
c:\users\x165896\appdata\local\programs\python\python36-32\Lib\json\encoder.py:199: in encode
    chunks = self.iterencode(o, _one_shot=True)
c:\users\x165896\appdata\local\programs\python\python36-32\Lib\json\encoder.py:257: in iterencode
    return _iterencode(o, 0)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <json.encoder.JSONEncoder object at 0x036BC630>
o = <MagicMock name='RestRequest().get_response().status_code' id='81333936'>

    def default(self, o):
        """Implement this method in a subclass such that it returns
            a serializable object for ``o``, or calls the base implementation
            (to raise a ``TypeError``).

            For example, to support arbitrary iterators, you could
            implement default like this::

                def default(self, o):
                    try:
                        iterable = iter(o)
                    except TypeError:
                        pass
                    else:
                        return list(iterable)
                    # Let the base class default method raise the TypeError
                    return JSONEncoder.default(self, o)

            """
        raise TypeError("Object of type '%s' is not JSON serializable" %
>                       o.__class__.__name__)
E       TypeError: Object of type 'MagicMock' is not JSON serializable

c:\users\x165896\appdata\local\programs\python\python36-32\Lib\json\encoder.py:180: TypeError

我想,我得到了这个,因为没有使用模拟的返回值。因此,创建了一个模拟对象,当然也不能被代码使用... 在pytest输出中:

o = <MagicMock name='RestRequest().get_response().status_code' id='81333936'>

所以,这意味着我没有嘲笑正确的事情。

我真正想要模拟的是RestRequest实例变量:&#39; response&#39;。这是一个Requests.response对象。

我成功地直接修补了MonAPPflaskRest.flaskRest.restRequest.RestRequest.response&#39;变量。输出听起来不错但assert_called()失败了。所以,给我一些怀疑。

所以,我真的不知道要嘲笑什么,实际上:实例变量&#39;响应&#39;对象&#39; RestRequest&#39;,上下文管理器,....

0 个答案:

没有答案