Turn off translations for unittest - python

I have some python code like
from pylons.i18n.translation import _
def get_message():
message = _(u"Translated message")
# interesting code to test
# [...]
return 'result'
which I would like to unittest like this:
class MyTest(TestCase):
def test_get_message(self):
assertTrue(get_message(), 'result')
Now running this test in nosetests gives me:
TypeError: No object (name: translator) has been registered for this thread
Is there a way to deactivate anything regarding translations when unittesting?

Let's say your production code is in my_module.py:
from unittest import TestCase
from mock import patch
from my_module import get_message
class MyTest(TestCase):
def test_get_message(self):
with patch("my_module._"):
result = get_message()
self.assertEqual("result", result)
With the patch your test changes the _() function to a MagicMock() object. Documentation here.
NOTE: mock is part of the standard library from Python 3.3 and onwards. Otherwise you should install it first using pip install mock.

Related

Is there a way to mock a complete bit of code in pytest using mock?

For instance, every time a test finds
database.db.session.using_bind("reader")
I want to remove the using_bind("reader")) and just work with
database.db.session
using mocker
Tried to use it like this in conftest.py
#pytest.fixture(scope='function')
def session(mocker):
mocker.patch('store.database.db.session.using_bind', return_value=_db.db.session)
But nothing has worked so far.
Code under test:
from store import database
results = database.db.session.using_bind("reader").query(database.Order.id).join(database.Shop).filter(database.Shop.deleted == False).all(),
and I get
AttributeError: 'scoped_session' object has no attribute 'using_bind' as an error.
Let's start with an MRE where the code under test uses a fake database:
from unittest.mock import Mock, patch
class Session:
def using_bind(self, bind):
raise NotImplementedError(f"Can't bind {bind}")
def query(self):
return "success!"
database = Mock()
database.db.session = Session()
def code_under_test():
return database.db.session.using_bind("reader").query()
def test():
assert code_under_test() == "success!"
Running this test fails with:
E NotImplementedError: Can't bind reader
So we want to mock session.using_bind in code_under_test so that it returns session -- that will make our test pass.
We do that using patch, like so:
#patch("test.database.db.session.using_bind")
def test(mock_bind):
mock_bind.return_value = database.db.session
assert code_under_test() == "success!"
Note that my code is in a file called test.py, so my patch call applies to the test module -- you will need to adjust this to point to the module under test in your own code.
Note also that I need to set up my mock before calling the code under test.

How to mock a base_class from an external module?

I'm trying to unit test a class which is derived from a base_class in an external module. In my dev/test environment I have not access to this external module, which means I have to somehow mock this base_class.
My test-code resides in a different file from the code I'm trying to test.
The problem can be summarized as follows:
my_class.py
import external_module
class MyClass(external_module.ExternalClass):
def test_method(self):
return "successful"
test_my_class.py
import sys
import unittest
from unittest.mock import MagicMock
sys.modules['external_module'] = MagicMock()
from my_class import MyClass
class TestMyClass(unittest.TestCase):
def test_first(self):
my_class = MyClass()
result = my_class.test_method()
self.assertEqual(result, "successful")
if __name__ == '__main__':
unittest.main()
Results
When running test_my_class.py the result are the following.
AssertionError: <MagicMock name='mock.ExternalClass.test_method()' id='140272215184664'> != 'successful'
Clearly since the external_module is mocked, even MyClass becomes an instance of a mock-object.
Similar posts
The problem is similar to as described in Python mock: mocking base class for inheritance, but has the difference that the base_class is from an external module.
Even How to mock a base class with python mock library show som similarities to my problem, though the solutions can not be directly applied.
Tries and failures
To get the import
import external_module
to work in my_class.py
sys.modules['external_module'] = MagicMock()
need to be set in test_my_class.py.
Though, this leads to that external_module.* becomes a Mock-instance.
You could create a helper module mocked_external_module, which can be imported from your tests and also contains a class base_class. Then you do the following in your test code:
import mocked_external_module
sys.modules['external_module'] = mocked_external_module
Plus, every method of your base_class that you need to mock you can create as a Mock or MagicMock.

monkeypatching not carrying through class import

I'm trying to test some code using pytest and need to change a function from some module. One of my imports also imports that function, but this is failing when I change the method using monkeypatch. Here is what I have:
util.py
def foo():
raise ConnectionError # simulate an error
return 'bar'
something.py
from proj import util
need_this = util.foo()
print(need_this)
test_this.py
import pytest
#pytest.fixture(autouse=True)
def fix_foo(monkeypatch):
monkeypatch.setattr('proj.something.util.foo', lambda: 'bar')
import proj.something
And this raises ConnectionError. If I change
test_this.py
import pytest
#pytest.fixture(autouse=True)
def fix_foo(monkeypatch):
monkeypatch.setattr('proj.something.util.foo', lambda: 'bar')
def test_test():
import proj.something
Then it imports with the monkeypatch working as expected. I've read though this and tried to model my testing from it, but that isn't working unless I import inside of a test. Why does the monkeypatch not do anything if it is just a normal import in the testing file?
That is because the fixture is applied to the test function not the entire code. autouse=True attribute just says that it should be used in every test

Python's mock.patch not patching class in unittest

I'm getting confused by using Mock in my python unittests. I've made this simplified version of my problem:
I have this dummy class and methods:
# app/project.py
class MyClass(object):
def method_a(self):
print(FetcherA)
results = FetcherA()
Which is using this class:
# app/fetch.py
class FetcherA(object):
pass
And then this test:
# app/tests/test.py
from mock import patch
from django.test import TestCase
from ..project import MyClass
class MyTestCase(TestCase):
#patch('app.fetch.FetcherA')
def test_method_a(self, test_class):
MyClass().method_a()
test_class.assert_called_once_with()
I would expect that running this test would pass and that print statement, for debugging, would output something like <MagicMock name=...>. Instead it prints out <class 'app.fetch.FetcherA'> and I get:
AssertionError: Expected to be called once. Called 0 times.
Why isn't FetcherA being patched?
OK, fourth time through I think I understood the 'Where to patch' section of the Mock docs.
So, instead of:
#patch('app.fetch.FetcherA')
I should use:
#patch('app.project.FetcherA')
Because we're testing the code in app.project.MyClass where FetcherA has been imported already. So at that point FetcherA is availably globally(?) within app.project.

Patch over a function imported inside another function

In order to avoid a circular import, I've been forced to define a function that looks like:
# do_something.py
def do_it():
from .helpers import do_it_helper
# do stuff
Now I'd like to be able to test this function, with do_it_helper patched over. If the import were a top level import,
class Test_do_it(unittest.TestCase):
def test_do_it(self):
with patch('do_something.do_it_helper') as helper_mock:
helper_mock.return_value = 12
# test things
would work fine. However, the code above gives me:
AttributeError: <module 'do_something'> does not have the attribute 'do_it_helper'
On a whim, I also tried changing the patch statement to:
with patch('do_something.do_it.do_it_helper') as helper_mock:
But that produced a similar error. Is there any way to mock this function, given the fact that I'm forced into importing it within the function where it's used?
You should mock out helpers.do_it_helper:
class Test_do_it(unittest.TestCase):
def test_do_it(self):
with patch('helpers.do_it_helper') as helper_mock:
helper_mock.return_value = 12
# test things
Here's an example using mock on os.getcwd():
import unittest
from mock import patch
def get_cwd():
from os import getcwd
return getcwd()
class MyTestCase(unittest.TestCase):
#patch('os.getcwd')
def test_mocked(self, mock_function):
mock_function.return_value = 'test'
self.assertEqual(get_cwd(), 'test')

Categories

Resources