Reputation: 2408
It took me hours to figure out how to patch the below code. The path to it was very much unexpected.
Depending on how I run the tests, and which dir I am in, I find the dotted path to the module to patch changes. This is really bad for unittesting. Which makes me think I am doing it wrong.
The file structure related to the code is:
loaders.py <-- Has a load_palette() func required to be patched
typers.py <-- Has `from . loaders import load_palette`, and calls load_palette()
render.py <-- Has a func that calls the typers func
tests/test_render.py <-- Tests for render which calls a func in render, which calls a func in typers, which calls load_palette()
In the code below __package__.replace('.tests', '.typers.load_palette')
takes the current path to the current package which could be:
bar.tests
orfoo.bar.tests
and builds the dotted path relatively so that is is correct. This seems very hackish. How is one supposed to safe guard against these kind of issues?
Ideally the dotted path would be ..typers.load_palette
but it did not accept the relative dotted path.
Heres the actual code:
# file: test_render.py
# Depending where one runs the test from, the path is different, so generate it dynamically
@mock.patch(__package__.replace('.tests', '.typers.load_palette'), return_value=mocks.palette)
class render_rule_Tests(SimpleTestCase):
def test_render_preset_rule(self, _): # _ = mocked_load_palette
...
Upvotes: 0
Views: 394
Reputation: 649
files layout as following:
$ tree issue
issue
├── __init__.py
├── loaders.py
├── renders.py
├── tests
│ ├── __init__.py
│ └── test_render.py
├── run_tests.sh
└── typers.py
1 directory, 7 files
the root package is issue
, you should always import modules from issue
, and patch issue.xxx.yyy
.
then run pytest
(or some other unittest tools) from the same path as tests
resident.
for example, run_tests.sh
is a shell script to run all test cases under tests
.
and test_render
may be like this
# file: test_render.py
# Depending where one runs the test from, the path is different, so generate it dynamically
@mock.patch('issue.typers.load_palette', return_value=mocks.palette)
class render_rule_Tests(SimpleTestCase):
def test_render_preset_rule(self, _): # _ = mocked_load_palette
...
Upvotes: 1
Reputation: 361
You can add the path of the "tests" directory using sys.path.insert.
In the top of "tests/test_render.py" add:
import sys
sys.path.insert(0, "<path/to/the/folder/tests/>")
# Depending where one runs the test from, the path is different, so generate it dynamically
@mock.patch(__package__.replace('.tests', '.typers.load_palette'), return_value=mocks.palette)
class render_rule_Tests(SimpleTestCase):
def test_render_preset_rule(self, _): # _ = mocked_load_palette
...
This will add the path in system paths where python interpreter. From there, the python interpreter can locate the relative imports.
Note: The safest option would be to add the absolute path to the tests folder. However, if it's not possible, add the shortest relative path possible.
Upvotes: 0