Run unittest.main() from a python invoke task - python

I am trying to run some unittest tests via a Python Invoke library, but my poor knowledge of Python prevents me from doing so.
This is the sample code I have:
my_tests.py
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
def main():
unittest.main()
if __name__ == '__main__':
main()
tasks.py
from invoke import task
#task
def tests(ctx):
main()
#task
def other_task(ctx):
print("This is fine")
def main():
import my_tests
import unittest
unittest.main(module='my_tests')
if __name__ == '__main__':
main()
And this is what I get:
C:\ittle_projects\invoke_unittest>python my_tests.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s
OK
C:\ittle_projects\invoke_unittest>python tasks.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
C:\ittle_projects\invoke_unittest>inv tests
E
======================================================================
ERROR: tests (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module 'my_tests' has no attribute 'tests'
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
The tests run fine from my_tests.py and from tasks.py, but when I use invoke stuff breaks.
How can I make it work or where should I look next?

The issue you are running into is that unittest.main() uses the command line arguments your program is called with to determine which tests to run. Since your program is being executed as inv tests, the first argument to your program is tests, so unittest is attempting to run tests for a module name tests which does not exist.
You can get around this by popping the last argument (tests) from the system arguments list:
import sys
from invoke import task
#task
def tests(ctx):
# Pop "tests" off the end of the system arguments
sys.argv.pop()
main()
#task
def other_task(ctx):
print("This is fine")
def main():
import my_tests
import unittest
unittest.main(module='my_tests')
if __name__ == '__main__':
main()

Related

On Running the test suite: Runs the test suite shows test passed Notification but displays "Empty Suite"

Here's my code but it shows no Tests found, and prints Empty Suite
import unittest
import time
from selenium import webdriver
class LoginTest(unittest.TestCase):
driver = webdriver.Chrome(executable_path="C:\\Users\\win\\Desktop\\chromedriver.exe")
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome(executable_path="C:\\Users\\win\\Desktop\\chromedriver.exe")
cls.driver.implicitly_wait(10)
def Test(self):
self.driver.get("https://opensource-demo.orangehrmlive.com/")
self.driver.find_element_by_id("txtPassword").send_keys("admin123")
self.driver.find_element_by_id("txtUsername").send_keys("Admin")
self.driver.find_element_by_id("btnLogin").click()
time.sleep(2)
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
print("Test Complete")
if __name__ == '__main__':
unittest.main()
I wrote this code, but on running my Test Suite it displays as follows:
Testing started at 2:47 PM ...
C:\PycharmProject\OrangeHRM\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2019.3.3\plugins\python-ce\helpers\pycharm\_jb_unittest_runner.py" --target LoginTest.LoginTest
Launching unittests with arguments python -m unittest LoginTest.LoginTest in C:\PycharmProject\OrangeHRM\ScriptsDemo\Tests
Ran 0 tests in 0.000s
OK
Process finished with exit code 0
No Tests were found
Empty suite
In unittest library exists a naming convention that all the tests start with 'test', this informs the test runner about which methods represent tests.
You have to change your 'Test' method to 'test'

Unittest not testing (python)

This is my code:
import unittest
from sallad.Puppgift import Kundenssallad
class Test_kundenssallad(unittest.TestCase):
def test_av_objekt(self):
namn = "Grekisksallad"
slutpris = 60
tillval = "gurka"
kundenssallad = Kundenssallad(namn, slutpris, tillval)
self.assertIsInstance(kundenssallad, Kundenssallad)
self.assertEqual(kundenssallad.slutpris, 60)
self.assertEqual(kundenssallad.tillval, "gurka")
if __name__ == "__main__":
unittest.main()
Upon running this code in PyCharm, I get:
Testing started at 11:32 ...
Process finished with exit code 0
I expected the program to print something like:
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
Why do the tests not seem to execute?
You have not told unittest what test suite to run.
pycharm not matching the if name == "main" ?
Try add some debug and print name.
Run it something like this:
if __name__ == "__main__":
unittest.main()
suite = unittest.TestLoader().loadTestsFromTestCase(Test_kundenssallad)
unittest.TextTestRunner(verbosity=2).run(suite)

Python Unit-Testing: In Nose is there a way to skip a test case from nose.run()?

I am writing a set of test cases say Test1, Test2 in a test module.
Is there a way to skip Test1 or selectively execute only Test2 in that module using the command nose.main()?
My module contains,
test_module.py,
class Test1:
setUp(self):
print('setup')
tearDown(self):
print('teardown')
test(self):
print('test1')
class Test2:
setUp(self):
print('setup')
tearDown(self):
print('teardown')
test(self):
print('test2')
I run it from a different python file using,
if __name__ == '__main__':
nose.main('test_module')
The notion of skipping test and not running a test are different in the context of nose: skipped tests will be reported as skipped at the end of the test result. If you want to skip the test you would have to monkey patch your test module with decorators or do some other dark magic.
But if you want to just not run a test, you can do it the same way you would do it from the command line: using --exclude option. It takes a regular expression of the test you do not want to run. Something like this:
import sys
import nose
def test_number_one():
pass
def test_number_two():
pass
if __name__ == '__main__':
module_name = sys.modules[__name__].__file__
nose.main(argv=[sys.argv[0],
module_name,
'--exclude=two',
'-v'
])
Running the test will give you:
$ python stackoverflow.py
stackoverflow.test_number_one ... ok
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK

Increasing logging verbosity of class being unit-tested in Python

I have a Python class that uses the logging module to provide some debug output:
File someclass.py:
import logging
class SomeClass:
def do_stuff(self):
# do some things
logging.debug("I just did some stuff")
# do some more stuff
return True
I do unit testing on this class with the unittest module
File test_someclass.py
import unittest
from someclass import SomeClass
class SomeClassTests(unittest.TestCase):
def test_do_stuff(self):
obj = SomeClass()
self.assertFalse(obj.do_stuff())
def main():
unittest.main()
if __name__ == '__main__':
main()
What I want to do is show the debug messages while I am running the unit tests. I tried to set the verbosity to debug from the unit test module:
import logging
# ....
def main():
unittest.main()
logging.basicConfig(level=logging.DEBUG)
This didn't work. What would be the way to achieve this? Even better would be enabling DEBUG verbosity for only one test.
UPDATE:
Apparently it works when running it from the Python shell, but not in PyDev (it probably uses a different test runner).
If you want to output debug messages on failures only, using nose test runner would be the easiest way to go since nose captures stdout and print it out on failures. It works out of the box:
$ nosetests test.py
F
======================================================================
FAIL: test_stuff (test.SomeClass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/../../test.py", line 7, in test_stuff
self.assertFalse(True)
AssertionError: True is not false
-------------------- >> begin captured stdout << ---------------------
I just did some stuff
--------------------- >> end captured stdout << ----------------------
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
where test.py contains:
from unittest import TestCase
class SomeClass(TestCase):
def test_stuff(self):
print "I just did some stuff"
self.assertFalse(True)
call unittest.main() from your main().
def main():
logging.basicConfig(level=logging.DEBUG)
unittest.main()
My output shows:
DEBUG:root:I just did some stuff
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
The basic example on unittests docs at: https://docs.python.org/2/library/unittest.html shows the simple way of calling and running a unit test from main.

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