Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Build composable Mock patches

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 tests
Octocat-spinner-32 .gitignore
Octocat-spinner-32 Makefile
Octocat-spinner-32 README.md
Octocat-spinner-32 multipatch.py
Octocat-spinner-32 requirements.pip
README.md

multipatch

An extension for composing Mock's patch context manager.

It is not uncommon for multiple unit tests to require much of the same fixture setup. Many times, this just means the same types are mocked out for the scope of a unit test. Mock's context managers do not compose well, meaning you can't easily build up a list of patches. The purpose of multipatch is to allow you to easily build a context manager for composing patches and control their lifetimes.

Here is an example using multipatch:

from mock import patch
from multpatch import multipatch
from unittest import TestCase


class Dependency1(object):
  def getNumber(self): 
    return 1


class Dependency2(object):
  def getNumber(self):
    return 2


class SUT(object):
  def foo(self):
    dep1 = Dependency1()
    dep2 = Dependency2()
    return dep1.getNumber() + dep2.getNumber()

class SUTTestCase(TestCase):
  def testFoo_mockDepsOnlyInCntx(self):
    sut = SUT()

    with multipatch(
      dep1=mock.patch('__main__.Dependency1'),
      dep2=mock.patch('__main__.Dependency2')
    ) as patcher:
      # reference dependencies by name
      patcher.dep1.getNumber.return_value = 3
      patcher.dep2.getNumber.return_value = 4

      result = sut.foo() # adds mocked return values

      self.assertEqual(7, result)

    result = sut.foo() # adds the original return values
    self.assertEqual(2, result)

The patch collection returned from multipatch can be returned from a function. New multipatches can be created by passing other multipatches to the multipatch function. This means you can easily compose patches together. Instead of dealing with the tuples that nest provides or with the one-and-done nature of patch.multiple. You can access your mock objects by name and reuse patches via composition.

Multipatches can also be used anywhere a patch can be used, except as a decorator. This means if you want to merge two multipatches with conflicting mock names, you can just make one of the multipatches a patch by giving it a name:

def getPatches():
    nested = multipatch(class1=patch('package.module.ClassName1'))
    patch = multipatch(nested=nested, class1=patch('package.module.ClassName2'))
    # patch.nested.class1
Something went wrong with that request. Please try again.