I have the following package:
tests.py
tests
__init__.py
test_module_a.py
test_module_b.py
In my tests.py file I do the following:
import unittest
from tests import *
if __name__ == "__main__":
unittest.main()
In my tests/__init__.py the following:
__all__ = ["test_module_a", "test_module_b"]
In my tests/test_module_a.py and tests/test_module_b.py files, I have the following:
import unittest
class TestMyModule(unittest.TestCase):
def test_something(self):
self.assertTrue(True)
When I run python tests.py, the submodules seem to be imported but my unittest.TestCase's are not run. Why? Thank.
Use a test loader and import explicitly every test case (to be more readable) :
import unittest
from test_module_a import TestMyModule1
from test_module_b import TestMyModule2
if __name__ == "__main__":
loader = unittest.TestLoader()
suite = unittest.TestSuite((loader.loadTestsFromTestCase(TestMyModule1),
loader.loadTestsFromTestCase(TestMyModule2),
)
)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
Related
I am encountering a weird import issue with Python module hoping to get some insight on.
I have the below following Folder Structure.
Folder Structure:
SomeProject
* Test/
* __init__.py
* TestModuleA.py
* TestModuleB.py
* TestModuleC.py
* __init__.py
* ModuleA.py
* ModuleB.py
* ModuleC.py
I was trying to run some of the test case with
python SomeProject/Test/TestModuleA.py
python SomeProject/Test/TestModuleB.py
python SomeProject/Test/TestModuleC.py
For some reason python SomeProject/Test/TestModuleA.py works fine, but python SomeProject/Test/TestModuleB.py came back with and error of ModuleNotFoundError: No module named 'SomeProject.ModuleB'.
I looked through the code, how ModuleA and ModuleB set up is pretty much the same, and how they are imported into TestModuleA and TestModuleB is same as well.
Also if I add from SomeProject.ModuleA import ModuleA from ModuleB it works fine.
I also tried running python -m unittest SomeProject/Test/TestModuleB.py and that seemed to work fine.
So I am wondering what's the discrepancy that could cause ModuleA and ModuleB to be different?
Test/__init__.py
name = 'Test'
Test/TestModuleA.py
from SomeProject.ModuleA import ModuleA
...
class TestModuleA(unittest.TestCase):
...
def suite():
"""Test Suite."""
# Create the Unit Test Suite
suite = unittest.TestSuite()
# Load a suite of all test cases contained in `testCaseClass`
test_module_a = unittest.defaultTestLoader.loadTestsFromTestCase(TestModuleA)
# Add the test suite
suite.addTest(test_module_a)
# Return the Test Suite
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
Test/TestModuleB.py
from SomeProject.ModuleB import ModuleB
...
class TestModuleB(unittest.TestCase):
...
def suite():
...
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
Test/TestModuleC.py
from SomeProject.ModuleC import ModuleC
...
class TestModuleC(unittest.TestCase):
...
def suite():
...
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
__init__.py
# Blank
ModuleA.py
class ModuleA:
__init__(self):
...
...
ModuleB.py
class ModuleB:
__init__(self):
...
...
ModuleC.py
class ModuleC:
__init__(self):
...
...
i try to run a unittest with unittest.TestLoader and unittest.TextTestRunner but get an ModuleNotFoundError everytime i try to run the 'main' test file (here: test_all.py). I have the following file structure:
src.
test_all.py
dir1.
__init__.py
module1.py
submodule1.py
test_module1.py
dir2.
__init__.py
module2.py
submodule2.py
test_module2.py
dir3.
...
The test_all.py file looks like this:
# test_all.py
import os
import unittest
loader = unittest.TestLoader()
suite = loader.discover(os.getcwd())
runner = unittest.TextTestRunner()
runner.run(suite)
And finally the structure of the single testcases look like this:
# test_module1.py
import unittest
from module1 import Module1
class Module1TestCase(unittest.TestCase):
def setUp(self):
# do something
def test_something(self):
# test test
def tearDown(self):
# do something
if __name__ == '__main__':
unittest.main()
So, running the test_all.py always results in an ModuleNotFoundError referencing to the from module1 import Module1 inside the TestCase test_module1.py (and the same in the following TestCases). As far as i can tell there are no circular dependencies. Maybe adding the current Path to the PythonPath would work, but it really makes no sense to me: on the one hand i run the test_all.pyas main in the current directory and on the other the unittest.TestLoader.discover() already takes the current path.
PS: I know that putting all the TestCases in one folder is way better. But first i want to figure out why this is not working. Thanks!
I have a bash script to execute my python tests and I would like to filter all test cases that have NOT_DONE in them
This is what I tried
python3 -m unittest discover -s ${FOLDER} -p 'test_((?!NOT_DONE).)*_ALL.py'
Input example :
test_word_NOT_DONE_more_words_alot_more_words_ALL.py <- This test shouldn't be executed
But this one should :
test_word_more_words_alot_more_words_ALL.py
Path Solution
Directory Structure
unittesting/
launcher.py
tests/
__init__.py
test_finished.py
test_NOT_DONE.py
folder/
__init__.py
test_finished2.py
test_NOT_DONE2.py
Inside each test file is print(__file__), nested under a TestCase method. Therefore, only if the module is imported and the test cases run, will it be executed.
Code:
import importlib
import os
import sys
import unittest
HOME = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, 'tests')
def check_file(file):
'''Check if file is test'''
return all((
'NOT_DONE' not in file,
file.endswith('.py'),
file != '__init__.py'
))
def find_paths(home=HOME):
'''Find all paths'''
os.chdir(HOME)
for root, dirs, files in os.walk('tests'):
for file in files:
if check_file(file):
if root != 'tests':
yield os.path.join(root[len('tests/'):], file)
else:
yield file
def normalize(path):
'''Normalize path to dotted name'''
path = os.path.splitext(path)[0]
unix = path.replace('/', '.')
return unix.replace('\\', '.')
def tests(paths=None):
'''Load and run tests'''
if paths is None:
paths = map(normalize, find_paths())
modules = (importlib.import_module(i) for i in paths)
suite = unittest.TestSuite()
loader = unittest.TestLoader()
for module in modules:
tests = loader.loadTestsFromModule(module)
suite.addTests(tests)
runner = unittest.TextTestRunner()
runner.run(suite)
if __name__ == '__main__':
tests()
As you can see, this gets unwieldly quickly, and very hard to manage. There's a simpler way. It runs, however.
$ python /home/alex/git/unittesting/launcher.py
tests/test_finished.pyc
.tests/folder/test_finished2.pyc
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Pythonic Solution
Inside each of my files that is not complete, I put the variable NOT_DONE = True, and each of my classes has a decorator skipif.
Directory Structure
unittesting/
launcher.py
tests/
__init__.py
test1.py
test2.py
folder/
__init__.py
test3.py
test4.py
In this example, test2 and test4 have NOT_DONE = True, while test1 and test3 have NOT_DONE = False.
An example file is as follows:
import unittest
NOT_DONE = False
# CASES
# -----
#unittest.skipIf(NOT_DONE, 'Reason')
class TestPrint(unittest.TestCase):
def test_print(self):
print(__file__)
if __name__ == '__main__':
unittest.main()
Now, to run I simply do:
$ python -m unittest discover tests
tests/test1.py
tests/folder/test3.py
.
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK (skipped=2)
Best Approach
Unfinished unittests should have a unittest.skipIf(True, 'Unfinished') line, so you get control not only at the module level, but also at the class or even method level. In the following example, I have one, finished unittest and one unfinished unittest. Running the example skips the first unittest, but runs the rest of the module.
import unittest
# CASES
# -----
#unittest.skipIf(True, 'Not Finished')
class TestPrint(unittest.TestCase):
def test_print(self):
print(__file__)
class TestPrinting(unittest.TestCase):
def test_print(self):
print(__file__)
if __name__ == '__main__':
unittest.main()
I am trying to code a suite test, I have one module which runs unit test correctly but I intend to add more modules and test them at once, so I have coded the following code:
#main.py
import unittest
from test.Services import TestOS
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTests( TestOS.TestOS() )
unittest.TextTestRunner().run(suite)
TestOS.py
import unittest
from app.Services.OS import OS
class TestOS(unittest.TestCase):
os = OS()
def setUp(self):
pass
def tearDown(self):
pass
def testOSName(self):
self.assertEquals(self.os.getPlatform(), 'Windows')
def testOSVersion(self):
self.assertEquals(self.os.getVersion(), '7')
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
After running it, I get this output:
Finding files... done.
Importing test modules ... done.
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
It didn't find any test, What's wrong with my code?
suite.addTest( TestOS.TestOS() ) works only if your testcase contains a runTest() function.
Otherwise you need a "TestLoader" to detect the functions of TestOS that start with "test*".
#main.py
import unittest
from test.Services import TestOS
if __name__ == '__main__':
suite = unittest.TestSuite()
tests = unittest.defaultTestLoader.loadTestsFromTestCase(TestOS)
suite.addTests(tests)
unittest.TextTestRunner().run(suite)
modify your setUp method as follows
def setUp(self):
self.os = OS()
pass
I need to make a big python suitecase consisted of other suitcases and testcase which I have already made to execute together.
How do I do this?
For example, here there is a suitecase (suiteFilter.py) which I want to add:
import testFilter1
import testFilter2
import unittest
import sys
def suite():
return unittest.TestSuite((\
unittest.makeSuite(testFilter1.TestFilter1),
unittest.makeSuite(testFilter2.TestFilter2),
))
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
And a testcase structure (Invoice.py):
from selenium import selenium
import unittest, time, re
from setup_tests import filename, fileForNrTest, username, password, server_url
fileW=open(filename,'a')
class TestInvoice(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*firefox", server_url)
self.selenium.start()
def test_invoice(self):
sel = self.selenium
[...]
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
Thank you!
You could give some additional information like the structure of your program / test cases and suites. The way I do it is define a suite() for each module. So I have say for UserServiceTest module:
def suite():
"""
Gather all the tests from this module in a test suite.
"""
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(UserServiceTest))
return test_suite
if __name__ == "__main__":
#So you can run tests from this module individually.
unittest.main()
Then I have a main test for each package:
def suite():
"""
Gather all the tests from this package in a test suite.
"""
test_suite = unittest.TestSuite()
test_suite.addTest(file_tests_main.suite())
test_suite.addTest(userservice_test.suite())
return test_suite
if __name__ == "__main__":
#So you can run tests from this package individually.
TEST_RUNNER = unittest.TextTestRunner()
TEST_SUITE = suite()
TEST_RUNNER.run(TEST_SUITE)
You can do this the recursevly until the root of your project. So main test from package A will gather all module in package A + main test from subpackages of package A and so on. I was assuming you-re using unittest since you didn't give any additional details but I think this structure can be applied to other python testing frameworks as well.
Edit: Well I'm not quite sure I fully understand your problem, but from what I can understand you want to add both the suite defined in suiteFilter.py and the testcase defined in Invoice.py in the same suite? If so why not just do in a mainTest.py for example:
import unittest
import suiteFilter
import Invoice
def suite()
test_suite = unittest.TestSuite()
test_suite.addTest(suiteFilter.suite())
test_suite.addTest(unittest.makeSuite(Invoice))
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
You can add tests and suites all the same to a test_suite.