Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock scope goes beyond current test

Tags:

python

mocking

I am mocking a module... here is my sample code

def test_validate(self):
    """Test Base Retriever Dataframe"""

    sampleQuoteClass = self.sampleQuoteClass('ThisQuote')

    bRet._getAsOfData = MagicMock(return_value=sampleQuoteClass)

    dataAsDataFrame = bVal.validate(metaDataName='MyNewQuote')
    self.assertTrue(len(dataAsDataFrame) > 0)

This works OK.

Problem is - bRet._getAsOfData is also mocked for the next tests, which incidentally resides in other test class.

This problem only occurs when all the tests are running together as a part of collection.

like image 633
Pankaj Singh Avatar asked Dec 16 '16 16:12

Pankaj Singh


People also ask

When should you not use a mock?

Only use a mock (or test double) “when testing things that cross the dependency inversion boundaries of the system” (per Bob Martin). If I truly need a test double, I go to the highest level in the class hierarchy diagram above that will get the job done. In other words, don't use a mock if a spy will do.

What is the difference between mock and MagicMock?

So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

What does @patch do in Python?

patch() as a Decorator If you want to mock an object for the duration of your entire test function, you can use patch() as a function decorator. These functions are now in their own file, separate from their tests. Next, you'll re-create your tests in a file called tests.py .

What is mock in unit test?

unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. unittest.mock provides a core Mock class removing the need to create a host of stubs throughout your test suite.


1 Answers

Sounds like you might want to patch the object instead of mocking it directly. You may need to adjust my example a bit to fit your code, but try something like this:

from mock import patch

def test_validate(self):
    """Test Base Retriever Dataframe"""

    sampleQuoteClass = self.sampleQuoteClass('ThisQuote')

    with patch('__main__.bRet') as mock_bRet:
        mock_bRet._getAsOfData.return_value = sampleQuoteClass

        dataAsDataFrame = bVal.validate(metaDataName='MyNewQuote')
        self.assertTrue(len(dataAsDataFrame) > 0)

When you patch the object, the mocking will be undone and the object will "go back to normal" once the with block exits, so the mocked state will not carry over to your other tests. It is also possible to use patch as a decorator, but I have always preferred to use it as a context manager. See the documentation linked above for examples of each usage.

Also, patching can be tricky in my experience, so I would suggest you read this useful bit of documentation on "where to patch" as well.

like image 178
elethan Avatar answered Sep 29 '22 19:09

elethan