Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python unit testing overriding module level functions

Related to Python unit testing code which calls OS/Module level python functions. During my unit testing I overload some python system calls to get my tests to drive different paths of a module. This technique called Monkey Patch (in the related question) for tests in isolation.

I am a bit worried about what happens when I run Python tests in parallel say like in "Nose". What happens when two tests are run in parallel and both want to mock the os.path.exists method?

Is there a way to selectively override a system or module function in the context of my test?

Take the following for example

fixture.py (say that is the module under test)

def my_func():
    some_stuff

test_fixture.py (say this is my test case)


class MyTest(unittest.TestCase):

    def test_mine(self):
         fixture.my_func = my_new_func
         fixture.execute_some_func_that_calls_my_func()
         #What happens if another test is executing at the same time and accesses
         #my_func I don't want it to start executing my_new_func?
like image 978
Kannan Ekanath Avatar asked Apr 24 '13 10:04

Kannan Ekanath


People also ask

What is @patch in Python?

This, along with its subclasses, will meet most Python mocking needs that you will face in your tests. The library also provides a function, called patch() , which replaces the real objects in your code with Mock instances.

How do you use assertRaises in Python?

There are two ways you can use assertRaises: using keyword arguments. Just pass the exception, the callable function and the parameters of the callable function as keyword arguments that will elicit the exception. Make a function call that should raise the exception with a context.

Is PyUnit the same as Unittest?

PyUnit is an easy way to create unit testing programs and UnitTests with Python. (Note that docs.python.org uses the name "unittest", which is also the module name.)


1 Answers

I don't know if it's the best way, but I generally use try ... finally when I'm doing this in tests, in order to set then restore changes during each test.

A brief example of this:

class TestRawInput(unittest.TestCase):

    def test_raw_input(self):
        orig_raw_input = raw_input
        try:
            raw_input = lambda _: 'Alice'
            self.assertEquals(raw_input(), 'Alice')
        finally:
            raw_input = orig_raw_input

An alternative could be to create a context manager for doing this, if it's a common operation in tests.

like image 200
Dave Challis Avatar answered Oct 04 '22 03:10

Dave Challis