Created
October 9, 2013 17:50
-
-
Save ramiroluz/6905320 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Patching and mocking Plone unittests with using mock | |
---------------------------------------------------- | |
The python mock module was created by Michael Foord and it has been integrated in the unittest module since python version 3.3. It's license is BSD as it is possible to see in the official `homepage of the project`_. | |
.. _homepage of the project: http://www.voidspace.org.uk/python/mock/index.html | |
It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. | |
You can use it to replace methods or properties, as it will be shown in the following examples. | |
The examples where extracted from the Module :py:mod:`plone.recipe.codeanalysis`. | |
Mocking a method | |
~~~~~~~~~~~~~~~~ | |
The first thing to do is import the necessary classes. | |
.. code-block:: python | |
:emphasize-lines: 3,4 | |
import unittest | |
from plone.recipe.codeanalysis.jshint import code_analysis_jshint | |
from mock import MagicMock | |
from mock import patch | |
Then the test method have to be decorated with @patch, the method needs an extra argument that represents the class being decorated. | |
.. code-block:: python | |
:emphasize-lines: 2,3 | |
class TestJSHint(unittest.TestCase): | |
@patch('subprocess.Popen') | |
def test_analysis_should_return_false(self, mock_class): | |
Inside the method a MagicMock is created. The desired value is set by passing a return_value parameter to the MagicMock class. In this case, communicate needs to return a tuple with two values, the second one is not necessary in the code being tested, you can choose whatever you want. | |
.. code-block:: python | |
:emphasize-lines: 3,5 | |
@patch('subprocess.Popen') | |
def test_analysis_should_return_false(self, mock_class): | |
mock_class().communicate = MagicMock( | |
return_value=(' x (E000) x ', 'IGNORED ERR',) | |
) | |
Finally you import the class being Mocked. The rest of the code is needed to give call the function being tested. | |
.. code-block:: python | |
:emphasize-lines: 1 | |
from subprocess import Popen | |
options = {'jshint-bin': 'FAKE_EXECUTABLE', | |
'jshint-exclude': 'FAKE_EXCLUDE', | |
'directory': 'FAKE_DIRECTORY', | |
'jenkins': 'False'} | |
self.assertFalse(code_analysis_jshint(options)) | |
Mocking a property | |
~~~~~~~~~~~~~~~~~~ | |
To mock a property you need to import an additional class. | |
.. code-block:: python | |
:emphasize-lines: 5 | |
import unittest | |
from plone.recipe.codeanalysis.flake8 import code_analysis_flake8 | |
from mock import MagicMock | |
from mock import patch | |
from mock import PropertyMock | |
In this use case, we don't care about the value of the method communicate, but the code being tested, code_analysis_flake8, expect the method communicate to return a tuple, so it is mocked up. A PropertyMock have to be created, then the property mock have to be assigned to the equivalent property name of the type being mocked. The rest of the code is similar. | |
.. code-block:: python | |
:emphasize-lines: 4,8 | |
class TestFlake8(unittest.TestCase): | |
@patch('subprocess.Popen') | |
def test_analysis_should_return_false(self, mock_class): | |
mock_class().communicate = MagicMock( | |
return_value=(' x Error should return false x ', 'IGNORED ERR',) | |
) | |
returncode = PropertyMock(return_value=1) | |
type(mock_class()).returncode = returncode | |
from subprocess import Popen | |
The mock technique is very useful when you don't want to depend on external libraries, in our example, the subprocess.Popen. | |
.. seealso:: | |
Module :py:mod:`mock` | |
Documentation of the :py:mod:`mock` module. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment