Running unit tests from the tested module - python

I have a bunch of modules and for each module I have a unittest based test. I want to define the main in each module to run its tests, but I get import errors because of import loops (specifically when I use from mymodule import myclass in the test.
I suspect this is a solved problem, so - what should I put in my module's main to run its corresponding test?

If I understand you correctly, you've got a file (lets call it mymodule.py) that looks like this:
import unittest
from mymoduletests import MyModuleTests
class myclass(object):
def somefunction(self, x):
return x*x
if __name__ == '__main__':
unittest.main()
and a separate file (lets call it mymoduletests.py) that looks something like this:
import unittest
from mymodule import myclass
class MyModuleTests(unittest.TestCase):
def test_somefunction(self):
m = myclass()
self.assertEqual(4, m.somefunction(2))
If you run mymodule.py you get the following result:
Traceback (most recent call last):
File "mymodule.py", line 2, in <module>
from mymoduletests import MyModuleTests
File "/Users/srgerg/Desktop/p/mymoduletests.py", line 2, in <module>
from mymodule import myclass
File "/Users/srgerg/Desktop/p/mymodule.py", line 2, in <module>
from mymoduletests import MyModuleTests
ImportError: cannot import name MyModuleTests
However, if you change mymodule.py to this:
class myclass(object):
def somefunction(self, x):
return x*x
if __name__ == '__main__':
import unittest
from mymoduletests import MyModuleTests
unittest.main()
and then run it, you get:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Have I understood you correctly?

Related

How to import and call 'main' functions from different files

I have bunch of python script files that i've created, and running them one by one. how can call these script files and run methods one by one from a different script file. I need little help as method in each file is named main() and i'm not sure how to import and call this method by the same name.
file1.py
import sys
def main():
#do something
if __name__ == '__main__':
main()
file2.py
import sys
def main():
#do something else
if __name__ == '__main__':
main()
You can simply import them as modules, and call the main() function for each
import file1, file2
file1.main()
file2.main()
I think the following syntax will work for you:
from file1 import main as main1
from file2 import main as main2
...
if you want to import main from file1.py into file2.py, you can do from file1 import main as main1 or some other name. This way, you give an alias to the function name. Alternatively, import file1 and then call file1.main()

How can I call a function from another file which contains an object defined in the main_file?

I have these two files:
main.py
def func_a():
return object_a.method()
class ClassA:
def __init__(self):
pass
def method(self):
return "k"
if __name__ == '__main__':
object_a = ClassA()
print(func_a())
import file_1
and file_1.py
import main
print(main.func_a())
I get these errors:
Traceback (most recent call last):
File "C:\Users\Utente\PycharmProjects\pythonProject\main.py", line 16, in <module>
import file_1
File "C:\Users\Utente\PycharmProjects\pythonProject\file_1.py", line 4, in <module>
print(main.func_a())
File "C:\Users\Utente\PycharmProjects\pythonProject\main.py", line 2, in func_a
return object_a.method()
NameError: name 'object_a' is not defined.
I would like to create object_a once by starting main.py, and have the object_a methods used by calling func_a from other files (which will be executed by main.py)
since __name__ != "__main__", object_a is never created in main.py. If you remove object_a = ClassA() from the if then it will run fine.
It is confusing, because you are expecting that having run the line: object_a = ClassA() that object_a will be attached to the main module.
You could try adding this as your first line of main.py:
print('top of main', __name__)
You will see this line execute twice as you are expecting, but with different outcomes.
What you should actually do to get what you want is to strip almost everything out of main.py except this:
if __name__ == '__main__':
object_a = ClassA()
print(func_a())
import file_1
plus enough imports to make this bit work, plus this: set_object_a(object_a)
Thus main.py can become:
if __name__ == '__main__':
set_object_a(ClassA())
print(func_a())
import file_1
Now everything else you had needs to go in another module all by itself like this:
# notmain.py
object_a = None
def set_object_a(a):
global object_a
object_a = a
def func_a():
return object_a.method()
class ClassA:
def __init__(self):
pass
def method(self):
return "k"
Now you can have any other modules do this and similar:
import notmain
print(notmain.func_a())

Chained imports for unit tests in python

There are a lot of threads on SO about unit tests and module imports, but still I'm having trouble importing modules into my testing script, when the module that I'm testing itself imports anoter module.
Here's my project structure:
Here's util1:
def add(x, y):
return x + y
if __name__ == "__main__":
pass
Here's util2:
from util1 import add
def add_then_string(x, y):
z = add(x, y)
return str(z)
if __name__ == "__main__":
pass
And here's the test file:
import unittest
class TestProject(unittest.TestCase):
def test_dummy(self):
self.assertTrue(True)
def test_add(self):
from Scripts.Project.util1 import add
self.assertEqual(add(1,1), 2)
def test_add_then_string(self):
from Scripts.Project.util2 import add_then_string
self.assertEqual(add_then_string(1,1), "2")
if __name__ == "__main__":
unittest.main()
The problem is that util2 can't find util1 when it's called from the test file via Scripts.Project.
I've put __init__.py files everywhere, but that doesn't help.
Here's the error when I run the tests:
Error
Traceback (most recent call last):
File path\to\dummy_test_project\UnitTests\test_project.py", line 13, in test_add_then_string
from Scripts.Project.util2 import add_then_string
File path\to\dummy_test_project\Scripts\Project\util2.py", line 1, in <module>
from util1 import add
ModuleNotFoundError: No module named 'util1'
How do I make this work so that I can test the add_then_string function in util2?
EDIT: As so often happens, something has occurred to me immediately after I post on SO. When I change the import in util2 to
from Scripts.Project.util1 import add
then the tests pass. My real repository has lots and lots of imports. Do I need to prepend Scripts.Project to all of them to get this to work?

AttributeError: 'TextTestResult' object has no attribute 'assertIn'

I am trying some Python with selenium, I have some defined tests in simpleUsageUnittest.py:
import unittest
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class PythonOrgSearch(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
# #unittest.skip("skip test_001")
def test_001_search_in_python_org(self):
driver = self.driver
driver.get("http://www.python.org")
self.assertIn("Python", driver.title)
elem = driver.find_element_by_name("q")
elem.send_keys("selenium")
elem.send_keys(Keys.RETURN)
# #unittest.skip("skip test_002")
def test_002_goole_and_stack_test_test(self):
driver_g = self.driver
driver_g.get("http://www.google.com")
self.assertIn("Google", driver_g.title)
body_g = driver_g.find_element_by_tag_name("body")
body_g.send_keys(Keys.CONTROL + 't')
driver_g.get("http://stackoverflow.com")
self.assertIn("Stack", driver_g.title)
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main(warnings = 'ignore')
Alone this set is working perfectly, but then I am trying to create some suite, testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.setUp)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.test_001_search_in_python_org)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.test_002_goole_and_stack_test_test)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.tearDown)
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
And while running this suite I encounter AttributeError: 'TextTestResult' object has no attribute 'assertIn', and since I dont exactly understand it I cannot fix it ;) If I delete assertIn lines in simpleUsageUnittest.py - then it is working again, but it is of course not what I want to do! Also Asserts in Python 2.7 not working for me example assertIn was not a big help since I am using Python 3.3.5 and Selenium 2.41.0. Can someone explain it to me? Or direct what attributes can I use to save my assert? ;)
Full trace:
C:\Users\zzz\Python\selenium_tutorial>python testTestSuite.py
Traceback (most recent call last):
File "testTestSuite.py", line 14, in <module>
result = unittest.TextTestRunner(verbosity=2).run(suite())
File "C:\Python33\lib\unittest\runner.py", line 168, in run
test(result)
File "C:\Python33\lib\unittest\suite.py", line 67, in __call__
return self.run(*args, **kwds)
File "C:\Python33\lib\unittest\suite.py", line 105, in run
test(result)
File "C:\Users\zzz\Python\selenium_tutorial\simpleUsageUnittest.py", line
18, in test_001_search_in_python_org
self.assertIn("Python", driver.title)
AttributeError: 'TextTestResult' object has no attribute 'assertIn'
SOLUTION
OK, it looks like in my testTestSuite.py, while executing, TextTestRunner treats "self.asserIn" lines in simpleUsageUnittest.py as self == TextTestRunner not as self == TestCase (I dont know if I explain/understand it correctly, but it is how i see it ;)). Here is fixed testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_001_search_in_python_org'))
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_002_goole_and_stack_test_test'))
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
'setUp' and 'tearDown' are missing because they are called automatically after every 'test'.
SOLUTION
OK, it looks like in my testTestSuite.py, while executing, TextTestRunner treats "self.asserIn" lines in simpleUsageUnittest.py as self == TextTestRunner not as self == TestCase (I dont know if I explain/understand it correctly, but it is how i see it ;)). Here is fixed testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_001_search_in_python_org'))
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_002_goole_and_stack_test_test'))
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
'setUp' and 'tearDown' are missing because they are called automatically after every 'test'.

Python unittesting: run tests in another module

I want to have the files of my application under the folder /Files, whereas the test units in /UnitTests, so that I have clearly separated app and test.
To be able to use the same module routes as the mainApp.py, I have created a testController.py in the root folder.
mainApp.py
testController.py
Files
|__init__.py
|Controllers
| blabla.py
| ...
UnitTests
|__init__.py
|test_something.py
So if in test_something.py I want to test one function that is in /Files/Controllers/blabla.py, I try the following:
import unittest
import Files.Controllers.blabla as blabla
class TestMyUnit(unittest.TestCase):
def test_stupid(self):
self.assertTrue(blabla.some_function())
if __name__ == '__main__':
unittest.main()
And then from the file testController.py, I execute the following code:
import TestUnits.test_something as my_test
my_test.unittest.main()
Which outputs no failures, but no tests executed
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
[Finished in 0.3s]
I have tried with a test that has no dependences, and if executed as "main" works, but when called from outside, outputs the same:
import unittest
def tested_unit():
return True
class TestMyUnit(unittest.TestCase):
def test_stupid(self):
self.assertTrue(tested_unit())
if __name__ == '__main__':
unittest.main()
Question: how do I get this to work?
The method unittest.main() looks at all the unittest.TestCase classes present in the context.
So you just need to import your test classes in your testController.py file and call unittest.main() in the context of this file.
So your file testController.py should simply look like this :
import unittest
from UnitTests.test_something import *
unittest.main()
In test_something.py, do this:
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestMyUnit, 'test'))
return suite
In testController.py, do this:
from TestUnits import test_something
def suite():
suite = unittest.TestSuite()
suite.addTest(test_something.suite())
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')
There is a workaround of using subprocess.call() to run tests, like:
import subprocess
args = ["python", "test_something.py"]
subprocess.call(args)

Categories

Resources