I have following code snippet -
import unittest
class SimpleWidgetTestCase(unittest.TestCase):
def setUp(self):
print 'setup'
def method_test(self):
print 'test method'
def tearDown(self):
print 'tear down'
if __name__ == "__main__":
unittest.main()
Output -
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
test method name should start with test. Replace method_test to test_method, and try again.
From unittest documentation:
A testcase is created by subclassing unittest.TestCase. The three
individual tests are defined with methods whose names start with the
letters test. This naming convention informs the test runner about
which methods represent tests.
Related
I am trying to patch some functions during either the setUp or setUpClass methods of a unittest.TestCase subclass.
Given a module patch_me_not.py
# patch_me_not.py
def patch_me(at):
print('I am not patched at {}.'.format(at))
def patch_me_not(at):
patch_me(at)
The following script produces more output that I would expect.
# main.py
import unittest
from unittest.mock import patch
from patch_me_not import patch_me_not
#patch('patch_me_not.patch_me', lambda x: None)
class PatchMeNotTests(unittest.TestCase):
#classmethod
def setUpClass(cls):
print('I am the setUpClass.')
patch_me_not('setUpClass')
def setUp(self):
print('I am the setUp.')
patch_me_not('setUp')
def test_print(self):
print('I am the test')
patch_me_not('test_print')
if __name__ == '__main__':
unittest.main()
The test script output is
I am the setUpClass.
I am not patched at setUpClass.
I am the setUp.
I am not patched at setUp.
I am the test
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Where I would not expect the two "I am not patched at..." lines in the output if the patch worked in setUp and setUpClass.
How can I get the mock patch to be applied in these methods?
I think you need to do this:
class PatchMeNotTests(unittest.TestCase):
#classmethod
#patch('patch_me_not.patch_me', lambda x: None)
def setUpClass(cls):
print('I am the setUpClass.')
patch_me_not('setUpClass')
#patch('patch_me_not.patch_me', lambda x: None)
def setUp(self):
print('I am the setUp.')
patch_me_not('setUp')
def test_print(self):
print('I am the test')
patch_me_not('test_print')
Patching your test case did not work because when patch is applied to TestCase it patches only test methods or to be more specific: methods that start with a configurable prefix patch.TEST_PREFIX which default value is "test". That's why your solution did not work.
Here is relevant quote from unittest docs
Patch can be used as a TestCase class decorator. It works by
decorating each test method in the class. This reduces the boilerplate
code when your test methods share a common patchings set. patch()
finds tests by looking for method names that start with
patch.TEST_PREFIX. By default, this is 'test', which matches the way
unittest finds tests. You can specify an alternative prefix by setting
patch.TEST_PREFIX.
In the future, I'll need to add many identical tests with different parameters. Now I am making a sample test suite:
import unittest
class TestCase(unittest.TestCase):
def __init__(self, methodName='runTest', param=None):
super(TestCase, self).__init__(methodName)
self.param = param
def test_something(self):
print '\n>>>>>> test_something: param =', self.param
self.assertEqual(1, 1)
if __name__ == "__main__":
suite = unittest.TestSuite()
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(TestCase)
for name in testnames:
suite.addTest(TestCase(name, param=42))
unittest.TextTestRunner(verbosity=2).run(suite)
It gets discovered by VS Code:
start
test.test_navigator.TestCase.test_something
When I run the tests, I don't receive the parameter:
test_something (test.test_navigator.TestCase) ...
>>>>>> test_something: param = None
ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
If I run this file directly, everything works as expected (note param = 42 part)
test_something (__main__.TestCase) ...
>>>>>> test_something: param = 42
ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
So it looks like VS Code is running the tests on its own just by using the discovered classes and ignoring TestSuite completely?
What am I doing wrong?
Thanks.
The problem is your code is in a if __name__ == "__main__" block which is only executed when you point Python directly at the file. So when the extension asks unittest to get all the tests and then run them for us it doesn't run the code in your if __name__ == "__main__" block (which is why it can find it but it doesn't do anything magical).
If you can get it to work using unittest's command-line interface then the extension should run it as you want it to.
The key is to implement the load_tests function:
def load_tests(loader, tests, pattern):
suite = unittest.TestSuite()
testnames = loader.getTestCaseNames(TestCase)
for name in testnames:
suite.addTest(TestCase(name, param=42))
suite.addTest(TestCase(name, param=84))
return suite
The documentation says:
If load_tests exists then discovery does not recurse into the package, load_tests is responsible for loading all tests in the package.
Now my tests run as expected.
P.S. Thanks to Brett Cannon for pointing me to Unit testing framework documentation
Using Python Unittest, here's an example of a test suite :
import unittest
# Here's our "unit".
def IsOdd(n):
return n % 2 == 1
# Here's our "unit tests".
class IsOddTests(unittest.TestCase):
def testOne(self):
self.failUnless(IsOdd(1))
def testTwo(self):
self.failIf(IsOdd(2))
def main():
unittest.main(verbosity=2)
if __name__ == '__main__':
main()
And the result :
testOne (__main__.IsOddTests) ... ok
testTwo (__main__.IsOddTests) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Is it possible to enhance the display of the tests, something like :
Testing ODD method
Testing with value is 1 (__main__.IsOddTests) ... ok
Testing with value is 2 (__main__.IsOddTests) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
What I'm trying to do, is in case of a lot of tests, displaying a Group name for each TestCase (that contains multiple tests), and a name for each tests (that should be more explicit than just the function name).
To do this simply set a docstring for your tests:
def testOne(self):
"""Test IsOdd(1)"""
self.failUnless(IsOdd(1))
def testTwo(self):
"""Test IsOdd(2)"""
self.failIf(IsOdd(2))
There's a bit of an art to picking docstrings for your tests that will make sense later. Don't be afraid to go back and refactor your things.
import unittest
import HTMLTestRunner
class TestClass1(unittest.TestCase):
def setUp(self):
pass
def case1(self):
assert 4 == 3
def case2(self):
assert 4 == 4
def tearDown(self):
pass
class TestClass2(unittest.TestCase):
def setUp(self):
pass
def case3(self):
assert 1 == 2
def tearDown(self):
pass
def suite():
suite = unittest.TestSuite()
suite.addTest(TestClass1(['case1','case2']))
suite.addTest(TestClass2('case4'))
return suite
test_suite = suite()
unittest.TextTestRunner(verbosity=2).run(test_suite)
fp = file('my_report.html', 'wb')
runner = HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='My unit test',
description='This demonstrates the report output by HTMLTestRunner.'
)
runner.run(test_suite)
I am trying to run all the methods in both the classes in a single run. However, the code above did not do so. In the suite function, I tried to add multiple tests from the classes but that also did not work and was giving an error.
From this answer at the question "Is test suite deprecated in PyUnit?":
"unittest.TestSuite is not necessary if you want to run all the tests in a single module as unittest.main() will dynamically examine the module it is called from and find all classes that derive from unittest.TestCase."
There's more in that answer about when unittest.TestSuite is useful.
That said, I needed to make some changes to get these tests to work. Firstly, unittest looks for functions with "test_" at their start. Also, unittest's assertEqual and similar methods should be used, instead of just Python's assert statement. Doing that and eliminating some unneeded code led to:
import unittest
class TestClass1(unittest.TestCase):
def test_case1(self):
self.assertEqual(4, 3)
def test_case2(self):
self.assertEqual(4, 4)
class TestClass2(unittest.TestCase):
def test_case3(self):
self.assertEqual(1, 2)
unittest.main()
This produced appropriate output (3 tests run with 2 failures), which I won't reproduce here in the interest of space.
Can I call a test method from within the test class in python? For example:
class Test(unittest.TestCase):
def setUp(self):
#do stuff
def test1(self):
self.test2()
def test2(self):
#do stuff
update: I forgot the other half of my question. Will setup or teardown be called only after the method that the tester calls? Or will it get called between test1 entering and after calling test2 from test1?
This is pretty much a Do Not Do That. If you want tests run in a specific order define a runTest method and do not name your methods test....
class Test_Some_Condition( unittest.TestCase ):
def setUp( self ):
...
def runTest( self ):
step1()
step2()
step3()
def tearDown( self ):
...
This will run the steps in order with one (1) setUp and one (1) tearDown. No mystery.
Try running the following code:
import unittest
class Test(unittest.TestCase):
def setUp(self):
print 'Setting Up'
def test1(self):
print 'In test1'
self.test2()
def test2(self):
print 'In test2'
def tearDown(self):
print 'Tearing Down'
if __name__ == '__main__':
unittest.main()
And the results is:
Setting Up
In test1
In test2
Tearing Down
.Setting Up
In test2
Tearing Down
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Now you see, setUp get called before a test method get called by unittest, and tearDown is called after the call.
All methods whose name begins with the string 'test' are considered unit tests (i.e. they get run when you call unittest.main()). So you can call methods from within the Test class, but you should name it something that does not start with the string 'test' unless you want it to be also run as a unit test.
sure, why not -- however that means test2 will be called twice -- once by test1 and then again as its own test, since all functions named test will be called.
Yes to both:
setUp will be called between each test
test2 will be called twice.
If you would like to call a function inside a test, then omit the test prefix.