I feel like this should be an easy mock, but I have not gotten it to work yet.
I am working off of the following directory structure:
module
├── utilities.py
├── order.py
├── test
│ ├── test_order.py
The relevant code is as follows:
-- utilities.py --
def get_file_path(order_number, file_extension):
# this is what I want to mock out
-- order.py --
from module.utilities import get_file_path
class Order():
# ...
#classmethod
def load_order(order_number, extension):
file_path = get_file_path(order_number, extension)
-- test_order.py --
import unittest
from unittest.mock import patch
from module.order import order
#patch('order.get_file_path')
def mock_file(_, extension):
if extension == 'json':
return static_file_path
class TestOrder(unittest.TestCase):
def test_load_order_by_number(self):
my_order = order.load_order(number, extension)
This is the first time that I have tried mocking in Python. From what I can tell, what I have should work, but whenever an Order calls get_file_path, it always uses the one in utilities.py.
I have tried:
decorating test_load_order_by_number
patching with module.order.get_file_path
I tried looking on SO but none of the solutions that I found helped, so I thought that I was just doing something obviously wrong that someone can point out.
It does not look like creating the patch outside of the class was getting picked up. It started working when I pulled the patch in as a decorator for the specific test.
class TestOrder(unittest.TestCase):
#patch('utilities.order.get_file_path')
def test_load_order_by_number(self, file_mock):
def mock_get_file_path(*args, **kwargs):
if kwargs.get('extension', None) == 'json':
return static_file_path
return None
file_mock.side_effect = mock_get_file_path
my_order = order.load_order(number, extension)
Related
I'm using Visual Studio Code and I want to use the panel Testing for my unittest tests. It's working for some but not all. Indeed when I import certains locals classes, VSCode doesn't recognize the test. If I remove the import the test is recognize.
Here is one of the class that I'm importing, I reduce it to the maximum:
class ConnectionAWS(InterfaceConnection):
def _connection(self) :
pass
def putFileInS3(self, file):
pass
Here the test :
import unittest
from repertoire.ConnectionAWS import ConnectionAWS
class TestConnectionAWS(unittest.TestCase):
def test_connection_success(self):
self.assertFalse(False)
def test_connection_failure(self):
self.assertFalse(False)
I didn't forget about init.py files.
Here the arborescence :
project
repertoire
ConnexionAWS.py
utils
Log.py
src
__init__.py
test
__init__.py
repertoire
__init__.py
test_connexionAWS.py
utils
__init__.py
test_log.py
test_log.py is recognized even if it's importing Log.py
Can someone explain to me where I'm wrong ?
First of all, the relevant portion of my project directory looks like:
└── my_package
├── my_subpackage
│ ├── my_module.py
| └── other_module.py
└── tests
└── my_subpackage
└── unit_test.py
I am writing some tests in unit_test.py that require mocking of an external resource at the module level. I would like to use a pytest fixture with module level scope and pytest monkeypatch to acomplish this. Here is a snippet of what I have tried in unit_test.py:
import unittest.mock as mock
import pytest
from my_package.my_subpackage.my_module import MyClass
#pytest.fixture(scope='function')
def external_access(monkeypatch):
external_access = mock.MagicMock()
external_access.get_something = mock.MagicMock(
return_value='Mock was used.')
monkeypatch.setattr(
'my_package.my_subpackage.my_module.ExternalAccess.get_something',
external_access.get_something)
def test_get_something(external_access):
instance = MyClass()
instance.get_something()
assert instance.data == 'Mock was used.'
Everything works just fine. But when I try to change line 8 from #pytest.fixture(scope='function') to #pytest.fixture(scope='module'), I get the following error.
ScopeMismatch: You tried to access the 'function' scoped fixture 'monkeypatch' with a 'module' scoped request object, involved factories
my_package\tests\unit_test.py:7: def external_access(monkeypatch)
..\..\Anaconda3\envs\py37\lib\site-packages\_pytest\monkeypatch.py:20: def monkeypatch()
Does anyone know how to monkeypatch with module level scope?
In case anyone wants to know, this is what the two modules look like as well.
my_module.py
from my_package.my_subpackage.other_module import ExternalAccess
class MyClass(object):
def __init__(self):
self.external_access = ExternalAccess()
self.data = None
def get_something(self):
self.data = self.external_access.get_something()
other_module.py
class ExternalAccess(object):
def get_something(self):
return 'Call to external resource.'
I found this issue which guided the way. I needed to make a few changes to the solution for module level scope. unit_test.py now looks like this:
import unittest.mock as mock
import pytest
from my_package.my_subpackage.my_module import MyClass
#pytest.fixture(scope='module')
def monkeymodule():
from _pytest.monkeypatch import MonkeyPatch
mpatch = MonkeyPatch()
yield mpatch
mpatch.undo()
#pytest.fixture(scope='module')
def external_access(monkeymodule):
external_access = mock.MagicMock()
external_access.get_something = mock.MagicMock(
return_value='Mock was used.')
monkeymodule.setattr(
'my_package.my_subpackage.my_module.ExternalAccess.get_something',
external_access.get_something)
def test_get_something(external_access):
instance = MyClass()
instance.get_something()
assert instance.data == 'Mock was used.'
This has gotten simpler as of pytest 6.2, thanks to the pytest.MonkeyPatch class and context-manager (https://docs.pytest.org/en/6.2.x/reference.html#pytest.MonkeyPatch). Building off Rich's answer, the monkeymodule fixture can now be written as follows:
#pytest.fixture(scope='module')
def monkeymodule():
with pytest.MonkeyPatch.context() as mp:
yield mp
#pytest.fixture(scope='function')
def external_access(monkeymodule):
external_access = mock.MagicMock()
external_access.get_something = mock.MagicMock(
return_value='Mock was used.')
monkeymodule.setattr(
'my_package.my_subpackage.my_module.ExternalAccess.get_something',
external_access.get_something)
I am developing multiple functions that answer a same problem but using different algorithm.
So the same input for all functions should generate the same output, that's why I wnted to use the same unit tests instead of having to create multiple tests with the same logic.
I was using the Python unittest framework, and I wanted to use an abstract test class to have the generic tests defined with a function variable so that I could just instantiate that generic function with the one I want to test in another normal test class. But it seems I can't instantiate the function variable in the child class.
So here is an example abstract class with generic tests for multiple functions.
class AbstractTestCase():
def test_generic_input_one(self):
result = self.function("input 1")
self.assertFalse(result)
def test_generic_input_two(self):
result = self.function("input 2")
self.assertTrue(result)
And here you would have a specific test class for the function_a that inherits the generic tests from the AbstractTestCase class and that implements its own.
class TestsFunctionA(AbstractTestCase, unittest.TestCase):
def setUp(self):
self.function = function_a
def test_specific_input(self):
result = self.assertTrue(self.function("specific input"))
self.assertTrue(result)
I am pretty sure it can be done, but I can't seem to find an example to see how to implement it. I would like to avoid code duplication.
What should be the simplest and best way to do it ?
I have been looking for it and got a couple of example like:
Eli Bendersky's Python unit testing: parametrized test cases
But what helped me the most was vegard's answer about making a class factory which would take parameters and create the TestCase accordingly
The function takes the parameters of the parameterised test case and the actual TestCase class can refer to them without any problems.
Here is an example, take a foo.py file with:
import unittest
def make_test_case(x):
class MyTestCase(unittest.TestCase):
def test_foo(self):
self.assertEquals(x, 1)
return MyTestCase
class ConcreteTestCase(make_test_case(1)):
pass
Then run the test(s):
python -m unittest -v foo
Basically this is very flexible and adapted really well to my usecase.
Basically you need to parametrized you tests with function.
For unittest you can use ddt
#ddt
class ProblemTestCase(unittest.TestCase):
def test_specific_input(self):
self.assertTrue(function_a("specific input"))
#data(function_a, function_b)
def test_generic_input_one(self, function):
result = function("input 1")
self.assertFalse(result)
#data(function_a, function_b)
def test_generic_input_two(self, function):
result = function("input 2")
self.assertTrue(result)
Alternatively you can use just plain OOP:
class AbstractTestCase(object):
def test_generic_input_one(self):
result = self.function("input 1")
self.assertFalse(result)
def test_generic_input_two(self):
result = self.function("input 2")
self.assertTrue(result)
class TestsFunctionA(AbstractTestCase, unittest.TestCase):
def function(self, param):
return function_a(param)
def test_specific_input(self):
self.assertTrue(self.function("specific input"))
class TestsFunctionB(AbstractTestCase, unittest.TestCase):
def function(self, param):
return function_b(param)
def test_another_specific_input(self):
self.assertTrue(self.function("another specific input"))
I came here searching for a way to test multiple implementations of the same function. My use case is testing student's submissions of different search algorithms that are all fed the same test data and should return the same results.
Sylhare's answer was easy to adopt but it does not hurt to share so here is how:
import unittest
def function_a():
result = ...
return result
def function_b():
result = ...
return result
def make_test(function):
class TestImplementation(unittest.TestCase):
def test_foo(self):
self.assertEquals(function, 1)
return TestImplementation
class TestImplementationA(make_test(function_a)):
pass
class TestImplementationB(make_test(function_b)):
pass
Given a structure
├── README.md
├── requirements.txt
├── test
│ ├── __init__.py
│ └── two_sum
│ ├── __init__.py
│ ├── base_test_suite.py
│ ├── test_brute_force.py
│ └── test_two_pass_hash_table.py
└── two_sum
├── __init__.py
├── brute_force.py
└── two_pass_hash_table.py
And there are brute-force and two-pass hash-table solutions (functions called two_sum) in the corresponding files in two_sum module.
And base_test_suite.py
class TestTwoSum:
def __init__(self, unittest, two_sum_func):
self.two_sum = two_sum_func
self.unittest = unittest
def test_it_returns_indices_of_two_numbers_that_add_up_to_target(self):
# given
numbers = [2, 7, 11, 15]
target = 9
# when
result = self.two_sum(numbers, target)
# then
self.unittest.assertEqual(result, [0, 1])
And test_brute_force.py
from unittest import TestCase
from test.two_sum.base_test_suite import TestTwoSum
from two_sum.brute_force import two_sum
class Test(TestCase):
def test(self):
case = TestTwoSum(self, two_sum)
case.test_it_returns_indices_of_two_numbers_that_add_up_to_target()
And test_two_pass_hash_table.py
from unittest import TestCase
from test.two_sum.base_test_suite import TestTwoSum
from two_sum.two_pass_hash_table import two_sum
class Test(TestCase):
def test(self):
case = TestTwoSum(self, two_sum)
case.test_it_returns_indices_of_two_numbers_that_add_up_to_target()
Then one can run python -m unittest which would run the same unit test for different solutions of the two sum problem.
I have a module I need to test that calls a function on import but I cannot call this function for various reasons. So I am mocking this function but even mocking it calls import.
For example I am testing mod1.py that looks like this:
import os
def bar():
return 'foo'
def dont_call():
os.listdir("C:\\tmp")
dont_call()
And my test looks something like this:
import mock
#mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()
The problem is os.listdir is called.
I cannot change mod1 so what can I do?
I am using python2.7.
To put this in context I am testing a module that opens a database connection on import which I do not agree with but I can see the reasoning behind it. Unfortunately I cannot access this database on my QA machine.
If you want code to 'not' be executed on import put them inside the following condition:
In mod1.py, do the following:
if __name__=="__main__":
dont_call()
This is because, by default when you import a python module, all the code in it gets executed. By adding the above condition, you are explicitly stating that dont_call() is to be called only when the file it run as a script and not when it is imported in other modules.
The workaround I found was to mock what dont_call was calling giving me something like this:
import mock
#mock.patch("os.listdir")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()
Check your dir
$tree.
test_shot/
├── mod1.py
├── __pycache__
│ └── mod1.cpython-310.pyc
└── test.py
Below code works fine for me.
mod1.py
import os
def bar():
return 'foo'
def dont_call():
os.listdir(".")
def call_this():
print('called this')
call_this()
dont_call()
test.py
import mock
#mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
import mod1
assert mod1.bar()=='foo'
if __name__=="__main__":
test_mod1()
Here is output:
$cd test_shot
$python3 test.py
called this
Suppose I have module1.py
from my_library import useful_function
def do_something(x):
return useful_function(x)
I am testing module2.py
from module1 import do_something
def do_something_else(x):
return do_something(x+1)
useful_function does database calls, and I would therefore like to stub it out to return a constant value.
How can I use mockito to stub out useful_function? I have tried importing my_library, and using
when( my_library ).useful_function('abc').thenReturn(...)
but that does not work. If I pause Eclipse and hover over the useful_function line inside do_something(), it appears that useful_function() has not been stubbed.
import module1
module1.useful_function = Mock(...)
return do_something(x+1)