About
Prerequisites
pip
is the easiest way to install mock.pip install mock
Source codes can be found here
Basic usage
Trivial class
We need a trivial class for demonstration how to write unit tests with mock.
import sys
class Person(object):
def speak(self, message):
"""Speak out given message in stdout
Parameters:
- `message`: A string going to speak
Return:
- `self`: This instance
"""
sys.stdout.write('%s\n' % message)
return self
def yell(self, message):
"""Yell out given message in both stdout and stderr
Parameters:
- `message`: A string going to yell
Return:
- `self`: This instance
"""
sys.stdout.write('%s\n' % message)
sys.stderr.write('%s!\n' % message)
return self
Then, we would like to test whether
speak()
and yell()
have been print
to stdout
and stderr
.
Test speak()
@mock.patch('use_mock.person.sys.stdout')
def test_speak(self, mockStdout):
self.myPerson.speak('haha')
mockStdout.write.assert_has_calls([
mock.call('haha\n')
])
Let’s go through this snippet line by line.
@mock.patch('use_mock.person.sys.stdout')
Mock out
sys.stdout
is critical when writing unit tests as it provides an easy way for us to manipulate outcomes of running them. For example, throwing a system exception like Out Of Memory etc. We can verify our codes can survive any specified strange scenarios as a result.
Back into our case, mocking
sys.stdout
allows us to capture any arguments passing to them an avoid them to be printed on console.def test_speak(self, mockStdout):
Prefix
test_
is required by the unittest
library. Otherwise, it won’t count as a test method
. ReferencemockStdout
is the mock outcome from previous decorator. self.myPerson.speak('haha')
Runs
speak()
from the instance self.myPerson
with argument haha
.
Expect to see
haha\n
in sys.stdout.write
after running this line. mockStdout.write.assert_has_calls([
mock.call('haha\n')
])
Verify argument
haha\n
has been passed to sys.stdout.write
.
Test yell()
@mock.patch('use_mock.person.sys')
def test_yell(self, mockSys):
self.myPerson.yell('haha')
mockSys.stdout.write.assert_has_calls([
mock.call('haha\n')
])
mockSys.stderr.write.assert_has_calls([
mock.call('haha!\n')
])
Contents are almost the same with previous section. However, there are slightly differences.
- We mock
use_mock.person.sys
instead ofuse_mock.person.sys.stdout
assert
runs onmockSys.stdout
andmockSys.stderr
The take away is that you can define how deep to mock by giving a concise path to
patch()
.
In our case, we mock out
sys
directly as we need to test sys.stderr
and sys.stdout
.Something extra
References
- https://docs.python.org/3/library/unittest.mock.html#module-unittest.mock
- https://docs.python.org/2/library/unittest.html
- https://stackoverflow.com/questions/8522689/how-to-temporary-hide-stdout-or-stderr-while-running-a-unittest-in-python
- https://stackoverflow.com/questions/12998908/is-it-possible-to-mock-pythons-built-in-print-function
沒有留言:
張貼留言