pytest can't mock a method when its called by another module - python

I can't seem to mock a method of one of my modules. I can mock it inside the unit test itself, but not in another method that calls it.
# Inside a module
from my_module import my_method
def some_method_that_calls_my_module_my_method(arg):
my_method(arg)
# In my unit test
#patch("my_module.my_method", mock.MagicMock(return_value="test1"))
def test_test():
# this works
print(my_module.my_method("slkdjflskdjfl"))
# this executes the method not the mock
some_method_that_calls_my_module_my_method("sldkfjlskdjflskdjf")
I'll add I really want to use the pytest decorator here if I can- I much prefer it to with.

Related

Run setup_class() class after class scope fixture defined in conftest

So, I have fixtures defined in conftest.py file with scope="class" as I want to run them before each test class is invoked. The conftest file is placed inside project root directory for it to be visible to every test module.
Now in one of the test modules, I have another setup function which I want to run once for that module only. But the problem is setup_class() method is called before running fixtures defined in conftest.py. Is this expected? I wanted it to be opposite because I want to use something done in the fixtures defined in conftest. How to do that?
Code -
conftest.py:
#pytest.fixture(scope="class")
def fixture1(request):
#set a
#pytest.fixture(scope="class")
def fixture1(request):
test_1.py:
#pytest.mark.usefixtures("fixture_1", "fixture_2")
class Test1():
#need this to run AFTER the fixture_1 & fixture_2
def setup_class():
#setup
#get a set in fixture_1
def test_1()
.....
I know that I could simply define a fixture in the test file instead of setup_class but then I will have to specify it in arguments of every test method in order it to be invoked by pytest. But suggestions are welcome!
I have exactly the same problem. Only now I have realized that the problem might be taht the setup_class is called before the fixture >-/
I think that this question is similar to this one
Pytest - How to pass an argument to setup_class?
And the problem is mixing the unittest and pytest methods.
I kind of did what they suggested - I ommitted the setup_class and created a new fixture within the particular test file,
calling the fixture in the conftest.py.
It works so far.
M.
The problem is that you can use the result of a fixture only in test function (or method) which is run by pytest. Here I can suggest a workaround. But of course I'm not sure if it suites your needs.
The workaround is to call the function from a test method:
conftest.py
#pytest.fixture(scope='class')
def fixture1():
yield 'MYTEXT'
test_1.py
class Test1:
def setup_class(self, some_var):
print(some_var)
def test_one(self, fixture1):
self.setup_class(fixture1)
Fixtures and setup_class are two different paradigms to initialize test functions (and classes). In this case, mixing the two creates a problem: The class-scoped fixtures run when the individual test functions (methods) run. On the other hand, setup_class runs before they do. Hence, it is not possible to access a fixture value (or fixture-modified state) from setup_class.
One of the solutions is to stop using setup_class entirely and stick with a fixtures-only solution which is the preferred way in pytest nowadays (see the note at the beginning).
# conftest.py or the test file:
#pytest.fixture(scope="class")
def fixture_1(request):
print('fixture_1')
# the test file:
class Test1():
#pytest.fixture(scope="class", autouse=True)
def setup(self, fixture_1, request):
print('Test1.setup')
def test_a(self):
print('Test1.test_a')
def test_b(self):
print('Test1.test_b')
Note that the setup fixture depends on fixture_1 and hence can access it.

Pytest Django function mocking APITestCase

I am trying to create tests involving sending GET requests to my API using pytest-django and I need a function used in the views to be mocked.
I have tried mocker from pytest-mock and unittest.mock.patch and every time I mock this function in some test case it remains mocked in the other tests as well.
First .py test file:
from unittest.mock import patch
from rest_framework.test import APITestCase
import pytest
#pytest.mark.django_db
class TestFirst(APITestCase):
#classmethod
def setUpClass(cls):
cls.patcher = patch(app.views.function)
cls.patcher.start()
#classmethod
def tearDownClass(cls):
cls.patcher.stop()
def test_something(self):
get_data = self.client.get('/some/url')
self.assertEqual(200, get_data.status_code)
and then followed by a test in some completely different .py file:
from rest_framework.test import APITestCase
import pytest
#pytest.mark.django_db
class TestSecond(APITestCase):
def test_something_else(self):
get_data = self.client.get('/some/url')
self.assertEqual(200, get_data.status_code)
When debugging the first test case, the method is patched correctly. However when running the second test, the method remains patched and the mock object keeps the number of calls received.
Am I missing something important?
EDIT: I tried both patching the file where the method is defined and name of the method in views, but always keep getting same result.
EDIT2: Worth noting that when I change the order of the tests, the second one completes correctly, but the first one is unable to have the method patched and calls it unpatched, therefore fails.
I resolved the issue by using the SimpleTestCase superclass. I have still no idea why this was happenning, but doesn't seem to be anymore.

Python unittest setUp function

I am relatively new to Python. According to unittest.setUp documentation:
setUp()
Method called to prepare the test fixture. This is called immediately before calling the test method; any exception raised by this method will be considered an error rather than a test failure. The default implementation does nothing.
My question about setUp is as follows:
In our testing code base, I have seen that we customized the Python testing framework by inheriting from unittest.TestCase. Originally, unittest.TestCase has names setUp and tearDown.In the customized class, we have setUpTestCase and tearDownTestCase. So each time those two functions will be called instead of those original counterparts.
My questions are:
How are those setUp and tearDown functions being called by the underlying test runner?
Is it required that those functions used to set up test cases should start with setUp and functions used to tear down test cases should start with tearDown? Or it can be named as any valid identifier?
Thank you.
setUp() and tearDown() methods are automatically used when they are available in your classes inheriting from unittest.TestCase.
They should be named setUp() and tearDown(), only those are used when test methods are executed.
Example:
class MyTestCase(unittest.TestCase):
def setUp(self):
self.setUpMyStuff()
def tearDown(self):
self.tearDownMyStuff()
class TestSpam(MyTestCase):
def setUpMyStuff(self):
# called before execution of every method named test_...
self.cnx = # ... connect to database
def tearDownMyStuff(self):
# called after execution of every method named test_...
self.cnx.close()
def test_get_data(self):
cur = self.cnx.cursor()
...

Patch - Patching the class introduces an extra parameter?

First time using patch. I've tried to patch one of my classes for testing. Without the patch attempting to run gets past the test function definition, but with the patch the test function definition apparently requires another parameter and I get a
TypeError: testAddChannelWithNamePutsChannel() takes exactly 1 argument (2 given)
Error. The test code is the following:
import unittest
import mock
from notification.models import Channel, addChannelWithName, deleteChannelWithName
class TestChannel(unittest.TestCase):
#mock.patch('notification.models.Channel')
def testAddChannelWithNamePutsChannel(self):
addChannelWithName('channel1')
Channel.put.assert_called_with()
Why does it require an extra parameter with the patch and what should this parameter be? Thank you much!
Patch passes in an instance of the patched object to your test method (or to every test method if you are patching at the class level). This is handy because it lets you set return values and side effects, or check the calls made
from unittest.mock import patch
#patch('some_module.sys.stdout')
def test_something_with_a_patch(self, mock_sys_stdout):
mock_sys_stdout.return_value = 'My return value from stdout'
my_function_under_test()
self.assertTrue(mock_sys_stdout.called)
self.assertEqual(output, mock_sys_stdout.return_value)
If you just want to literally patch something out to ignore it then you can call patch with the following invocation
from unittest.mock import patch, Mock
#patch('some_module.sys.stdout', Mock())
def test_something_with_a_patch(self):
That replaces sys.stdout in the some_module with a Mock object and does not pass it to the method.
patch passes the patched object to the test function. Its documented here:
patch as function decorator, creating the mock for you and passing it
into the decorated function:
>>>
>>> #patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
... print(mock_class is SomeClass)
...
>>> function(None)
True

How can I create a class-scoped test fixture in pyUnit?

I am unit testing mercurial integration and have a test class which currently creates a repository with a file and a clone of that repository in its setUp method and removes them in its tearDown method.
As you can probably imagine, this gets quite performance heavy very fast, especially if I have to do this for every test individually.
So what I would like to do is create the folders and initialize them for mercurial on loading the class, so each and every unittest in the TestCase class can use these repositories. Then when all the tests are run, I'd like to remove them. The only thing my setUp and tearDown methods then have to take care of is that the two repositories are in the same state between each test.
Basically what I'm looking for is a python equivalent of JUnit's #BeforeClass and #AfterClass annotations.
I've now done it by subclassing the TestSuite class, since the standard loader wraps all the test methods in an instance of the TestCase in which they're defined and puts them together in a TestSuite. I have the TestSuite call the before() and after() methods of the first TestCase. This of course means that you can't initialize any values to your TestCase object, but you probably want to do this in your setUp anyway.
The TestSuite looks like this:
class BeforeAfterSuite(unittest.TestSuite):
def run(self, result):
if len(self._tests) < 1:
return unittest.TestSuite.run(self, result)
first_test = self._tests[0]
if "before" in dir(first_test):
first_test.before()
result = unittest.TestSuite.run(self, result)
if "after" in dir(first_test):
first_test.after()
return result
For some slightly more finegrained control I also created the custom TestLoader which makes sure the BeforeAfterSuite is only used to wrap test-method-TestCase objects in, which looks like this:
class BeforeAfterLoader(unittest.TestLoader):
def loadTestsFromTestCase(self, testCaseClass):
self.suiteClass = BeforeAfterSuite
suite = unittest.TestLoader.loadTestsFromTestCase(self, testCaseClass)
self.suiteClass = unittest.TestLoader.suiteClass
return suite
Probably missing here is a try/except block around the before and after which could fail all the testcases in the suite or something.
from the Python unittest documentation :
setUpClass() :
A class method called before tests in an individual class run. setUpClass is called with the class as the only argument and must be decorated as a classmethod():
#classmethod
def setUpClass(cls):
...
New in version 2.7.
tearDownClass() :
A class method called after tests in an individual class have run. tearDownClass is called with the class as the only argument and must be decorated as a classmethod():
#classmethod
def tearDownClass(cls):
...

Categories

Resources