[Fixed]-How can I mock a method globally for all tests in python

6πŸ‘

βœ…

I don’t use Django and maybe there is some idiomatic way to do it well in Django.

My approach to this kind of problem is to create my own TestCase class that extend from unittest.TestCase and override setUpClass()/tearDownClass/setUp()/tearDown() to set up the mock/patch that I need globally in my tests (or at least in a part of them).

Now every time I need it instead of importing unittest.TestCase module I’m importing myunittest.TestCase

Example: myunittest.py

import unittest

class TestCase(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        super(TestCase, cls).setUpClass()
        # Init your class Mock/Patch

    @classmethod
    def tearDownClass(cls):
        # Remove Mocks or clean your singletons
        super(TestCase, cls).tearDownClass()

    def setUp(self):
        super(TestCase, self).setUp()
        # Init your obj Mock/Patch

    @classmethod
    def tearDown(self):
        # ... if you need it
        super(TestCase, self).tearDown()

And in your tests:

from myunittest import TestCase

    class Test(TestCase):
        ... Your test

7πŸ‘

Two ways that I have used in a big django project

Assuming a: my_mock = patch("myapp.mymodule.MyClass.my_method")

1) You can add a mock inside a custom test runner class:

from mock import patch
from django.test.runner import DiscoverRunner

class MyTestRunner(DiscoverRunner):
    @my_mock
    def run_tests(self, test_labels, **kwargs):
         return super(MyTestRunner, self).run_tests(test_labels, **kwargs)

2) You can add a mock on a custom base test class:

from mock import patch
from django.test import TestCase

class MyTestCase(TestCase):

   def setUp(self):
      super(MyTestCase, self).setUp()
      my_mock.start()

   def tearDown(self):
      super(MyTestCase, self).tearDown()
      my_mock.stop()
πŸ‘€djangonaut

0πŸ‘

Below are two methods to implement mocking.

Method 1: With modifications to production code:

You can create a pseudo-package and import it for testing instead of importing the original package. This check-based-import could be done at the beginning of every file.

For example:

import os
    if 'TEST' in os.environ:
        import pseudoTime as time
    else:
        import time

print time.time

Method 2: No modifications to production code:

In your test program, you could import the utility package ( the package containing the email function described in the question) and overwrite the utility function.

For example:

Consider the following code:

import time
def function():
    return time.time()

The test code could do the following:

import code
import time

def helloWorld():
    return "Hello World"

print "Before changing ...", code.function()
oldTime = time.time # save
time.time = helloWorld
print "After changing ...", code.function()
time.time = oldTime # revert back

The output for above test was:

Before changing ... 1456487043.76
After changing ... Hello World

Thus the test code can import the utility file, overwrite the function it provides and then run the tests on production code.

This method is superior as it does not change production code.

Leave a comment