Reputation: 9980
I have a (python3) package that has completely different behaviour depending on how it's init()
ed (perhaps not the best design, but rewriting is not an option). The module can only be init()
ed once, a second time gives an error. I want to test this package (both behaviours) using py.test.
Note: the nature of the package makes the two behaviours mutually exclusive, there is no possible reason to ever want both in a singular program.
I have serveral test_xxx.py
modules in my test directory. Each module will init the package in the way in needs (using fixtures). Since py.test
starts the python interpreter once, running all test-modules in one py.test run fails.
Monkey-patching the package to allow a second init()
is not something I want to do, since there is internal caching etc that might result in unexplained behaviour.
Upvotes: 17
Views: 15635
Reputation: 576
Delete all your module imports and also your tests import that also import your modules:
import sys
for key in list(sys.modules.keys()):
if key.startswith("your_package_name") or key.startswith("test"):
del sys.modules[key]
you can use this as a fixture by configuring on your conftest.py
file a fixture using the @pytest.fixture
decorator.
Upvotes: 6
Reputation: 662
To reload a module, try using the reload()
from library importlib
Example:
from importlib import reload
import some_lib
#do something
reload(some_lib)
Also, launching each test in a new process is viable, but multiprocessed code is kind of painful to debug.
Example
import some_test
from multiprocessing import Manager, Process
#create new return value holder, in this case a list
manager = Manager()
return_value = manager.list()
#create new process
process = Process(target=some_test.some_function, args=(arg, return_value))
#execute process
process.start()
#finish and return process
process.join()
#you can now use your return value as if it were a normal list,
#as long as it was assigned in your subprocess
Upvotes: 6
Reputation: 1902
Once I had similar problem, quite bad design though..
@pytest.fixture()
def module_type1():
mod = importlib.import_module('example')
mod._init(10)
yield mod
del sys.modules['example']
@pytest.fixture()
def module_type2():
mod = importlib.import_module('example')
mod._init(20)
yield mod
del sys.modules['example']
def test1(module_type1)
pass
def test2(module_type2)
pass
The example/init.py had something like this
def _init(val):
if 'sample' in globals():
logger.info(f'example already imported, val{sample}' )
else:
globals()['sample'] = val
logger.info(f'importing example with val : {val}')
output:
importing example with val : 10
importing example with val : 20
No clue as to how complex your package is, but if its just global variables, then this probably helps.
Upvotes: 2
Reputation: 2417
I have the same problem, and found three solutions:
Upvotes: 0