Skip to content

Instantly share code, notes, and snippets.

@keegoo
Last active March 9, 2020 03:16
Show Gist options
  • Save keegoo/831531e69437a8ef6d2292d8d3819019 to your computer and use it in GitHub Desktop.
Save keegoo/831531e69437a8ef6d2292d8d3819019 to your computer and use it in GitHub Desktop.
# ========== theory ==========
#
# Mock and MagicMock are all classes in `unitest.mock` library.
#
# ---------- The MagicMock Class ----------
# A MagicMock instance can:
# * capture the arguments that the method is called with
# * count how many times it's called
# * return values that we specify
# * return the same or different values each time the mocked method is called
# * be made to raise errors
#
# ---------- The Mock Class ----------
# `unittest.mock` provides a core Mock class removing the need to create a host of stubs throughout your test suite.
#
# MagicMock is a subclass of Mock with all the magic methods pre-created and ready to use.
#
# The patch() decorators makes it easy to temporarily replace classes in a particular module with a
# Mock object. By default patch() will create a MagicMock for you.
#
# ---------- pytest-mock ----------
# It provides a `mocker` fixture which is a thin-wrapper around the patching API provided by the mock package.
# The `mocker` fixture has the same API as `mock.patch`.
# The `mocker` also provides other nice utilities such as `spy` and `stub`.
# Other names like `Mock`, `MagicMock` etc are also accessible from `mocker`.
#
# Consider following examples
#
# In Mock directly
from unittest import mock
m = mock.MagicMock()
assert isinstance(m.foo, mock.MagicMock)
assert isinstance(m.bar, mock.MagicMock)
assert isinstance(m(), mock.MagicMock)
assert m.foo is not m.bar is not m()
# In mocker fixture
from unittest import mock
import pytest
def test_do_something(mocker):
m = mocker.MagicMock()
assert isinstance(m.foo, mock.MagicMock)
assert isinstance(m.bar, mock.MagicMock)
assert isinstance(m(), mock.MagicMock)
assert m.foo is not m.bar is not m()
# ---------- Assertion for Mock object ----------
m = MagicMock()
m.assert_called()
m.assert_called_once()
m.assert_called_with()
m.assert_called_once_with()
m.assert_any_call()
m.assert_has_calls()
m.assert_not_called()
# ========== mocker.path() requires a path to the function being patched ==========
# Consider following examples
# Example 1
import pytest
def foo():
return 'should not be called'
def get_foo():
return foo()
def test_get_foo(mocker):
m = mocker.patch(__name__ + '.foo', return_value='bar') # notice: `__name__`
assert get_foo() == 'bar'
# Example 2
# foo.py
def foo():
return 'should not be called'
# bar.py
from foo import foo
def get_foo():
return foo()
# test_something.py
import pytest
from bar import get_foo
def test_get_foo(mocker):
m = mocker.patch('bar.foo', return_value='bar') # notice: `bar.foo`
assert get_foo() == 'bar'
# ========== assert input for mocked function ==========
import pytest
def do_something(client, name):
client.greeting(name)
def test_it(mocker):
obj = mocker.MagicMock()
do_something(obj, 'Jim')
obj.greeting.assert_called_with('Jim')
# ========== mock standard library ==========
import os
class UnixFS:
@staticmethod
def rm(filename):
os.remove(filename)
def test_unix_fs(mocker):
m = mocker.patch('os.remove')
UnixFS.rm('file')
m.assert_called_once_with('file')
# ========== Pytest assert raise exception ==========
import re
import pytest
def check_email_format(email):
if not re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email):
raise Exception("Invalid email format")
else:
return "Email format is ok"
def test_email_exception():
with pytest.raises(Exception) as e:
assert check_email_format("bademail.com")
assert str(e.value) == "Invalid email format"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment