Creating a Unit testcase Class within a function not running testcases - python

I need to create a unit test class with a function so i can call the function when some event is triggered. I am using the below method but testcases are not executing
gp = r"somefile"
def MyFunc():
if os.path.exists(gp):
print("yes")
class First__Test_Cases(unittest.TestCase):
def test_001(self):
print("1")
def test__002(self):
print("2")
if __name__ == '__main__':
unittest.main()
First__Test_Cases()
else:
print("fail")
MyFunc()
output - Ran 0 tests in 0.000s

Remove MyFunc() and global parts, it should only contain class and main
mytestfile.py
import unittest
class First_Test_Cases(unittest.TestCase):
def test_001(self):
Pass
def test__002(self):
Pass
if __name__ == '__main__':
unittest.main()
Then run
python mytestfile.py
And all tests in the class will be executed:
...
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
You can read more and see more examples in the documentation
If you need to have a function call the test, you should do that in a separate file. Check this post: Run unittests from a different file

According to what I understood from your change in code, this is your use case:
Tests should be run only if a certain file exists. Otherwise, they should be skipped.
For this use case, I would suggest the following solution:
import os
import unittest
gp = "some_file.txt"
msg = "file {} does not exist".format(gp)
class First_Test_Cases(unittest.TestCase):
#unittest.skipUnless(os.path.exists(gp), msg)
def test_001(self):
pass
#unittest.skipUnless(os.path.exists(gp), msg)
def test_002(self):
pass
if __name__ == '__main__':
unittest.main()
The output would be the following if the file does not exist:
ss
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK (skipped=2)
and this one, if it exists:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
In case if you want your tests to fail, just change the code in this way:
import os
import unittest
gp = "some_file.txt"
msg = "file {} does not exist".format(gp)
class First_Test_Cases(unittest.TestCase):
def test_001(self):
self.assertTrue(os.path.exists(gp), msg) # add this line
# your code
def test_002(self):
self.assertTrue(os.path.exists(gp), msg) # add this line
# your code
Then, the output would be the following:
FF
======================================================================
FAIL: test_001 (__main__.First_Test_Cases)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 11, in test_001
self.assertTrue(os.path.exists(gp), msg)
AssertionError: file some_file.txt does not exist
======================================================================
FAIL: test_002 (__main__.First_Test_Cases)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 15, in test_002
self.assertTrue(os.path.exists(gp), msg)
AssertionError: file some_file.txt does not exist
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=2)

Related

How to skip some test cases in test discovery?

In python 2.7, I use unittest module and write tests, while some of them are skipped with #unittest.skip.
My codes looks like:
import unittest
class MyTest(unittest.TestCase):
def test_1(self):
...
#unittest.skip
def test_2(self):
...
I have lots of such test files in a folder, and I use test discovery to run all these test files:
/%python_path/python -m unittest discover -s /%my_ut_folder% -p "*_unit_test.py"
This way, all *_unit_test.py files in the folder will be ran. In above codes, both test_1 and test_2 will be ran. What I want is, all test cases with #unittest.skip, e.g. test_2 in my above codes, should be skipped. How do I achieve this?
Any help or suggestion will be greatly appreciated!
Try adding a string argument to the #unittest.skip decorator, such as in the following:
import unittest
class TestThings(unittest.TestCase):
def test_1(self):
self.assertEqual(1,1)
#unittest.skip('skipping...')
def test_2(self):
self.assertEqual(2,4)
Running without the string argument in python 2.7 gives me the following:
.E
======================================================================
ERROR: test_2 (test_test.TestThings)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib64/python2.7/functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'TestThings' object has no attribute '__name__'
----------------------------------------------------------------------
Ran 2 tests in 0.001s
whereas running with text in python 2.7 gives me:
.s
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK (skipped=1)
See https://docs.python.org/3/library/unittest.html or https://www.tutorialspoint.com/unittest_framework/unittest_framework_skip_test.htm for more details

Unexpected behavior from unittest.mock.patch

What is wrong with my code below?
I'm expecting assert call_func_once_with("b") to throw an error as call_func was passed 'a'. I confimed that the function was indeed called once and with argument 'a'.
from unittest.mock import Mock, patch
def call_func(x):
pass
#patch("__main__.call_func")
def test_call_func(call_func):
call_func("a")
assert call_func.called_once_with("b")
assert call_func.called == 1
print(call_func.call_args)
test_call_func()
Output:
call('a')
You're not the first person to notice strange things with these types of assertions (see Magic mock assert_called_once vs assert_called_once_with weird behaviour)
For what it's worth, I can only advise that you try to create a test class which inherits from unittest.TestCase and then use the assertEqual method to get more consistent test behaviour:
import unittest
from unittest.mock import patch, call
def call_func(x):
pass
class MyTests(unittest.TestCase):
#patch("__main__.call_func")
def test_call_func(self, call_func_mock):
call_func_mock("a")
# assert call_func_mock.called == 1
# assert call_func_mock.called_once_with("b")
self.assertEqual(call_func_mock.call_count, 1)
self.assertEqual(call_func_mock.call_args_list[0], call("b"))
print(call_func_mock.call_args)
unittest.main()
This gives the following (expected) results:
F
======================================================================
FAIL: test_call_func (__main__.MyTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python36\lib\unittest\mock.py", line 1179, in patched
return func(*args, **keywargs)
File "C:/scratch.py", line 16, in test_call_func
self.assertEquals(call_func_mock.call_args_list[0], call("b"))
AssertionError: call('a') != call('b')
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
Process finished with exit code 1

Filter tests after discover

I'm currently running my tests like this:
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner().run(tests)
Now I want to run a specific test knowing his name (like test_valid_user) but not knowing his class. If there is more than one test with such name than I would like to run all such tests. Is there any way to filter tests after discover?
Or maybe there are other solutions to this problem (please note that it shouldn't be done from command line)?
You can use the unittest.loader.TestLoader.testMethodPrefix instance variable to change the test methods filter according to a different prefix than "test".
Say you have a tests directory with this king of unit tests:
import unittest
class MyTest(unittest.TestCase):
def test_suite_1(self):
self.assertFalse("test_suite_1")
def test_suite_2(self):
self.assertFalse("test_suite_2")
def test_other(self):
self.assertFalse("test_other")
You can write your own discover function to discover only test functions starting with "test_suite_", for instance:
import unittest
def run_suite():
loader = unittest.TestLoader()
loader.testMethodPrefix = "test_suite_"
suite = loader.discover("tests")
result = unittest.TestResult()
suite.run(result)
for test, info in result.failures:
print(info)
if __name__ == '__main__':
run_suite()
remark: the argument "tests" in the discover method is a directory path, so you may need to write a fullpath.
As a result, you'll get:
Traceback (most recent call last):
File "/path/to/tests/test_my_module.py", line 8, in test_suite_1
self.assertFalse("test_suite_1")
AssertionError: 'test_suite_1' is not false
Traceback (most recent call last):
File "/path/to/tests/test_my_module.py", line 11, in test_suite_2
self.assertFalse("test_suite_2")
AssertionError: 'test_suite_2' is not false
Another simpler way, would be to use py.test with the -k option which does a test name keyword scan. It will run any tests whose name matches the keyword expression.
Although that is using the command-line which you didn't want, please not that you can call the command-line from your code using subprocess.call to pass any arguments you want dynamically.
E.g.: Assuming you have the following tests:
def test_user_gets_saved(self): pass
def test_user_gets_deleted(self): pass
def test_user_can_cancel(self): pass
You can call py.test from cli:
$ py.test -k "test_user"
Or from code:
return_code = subprocess.call('py.test -k "test_user"', shell=True)
There are two ways to run a single test method:
Command line:
$ python -m unittest test_module.TestClass.test_method
Using Python script:
import unittest
class TestMyCode(unittest.TestCase):
def setUp(self):
pass
def test_1(self):
self.assertTrue(True)
def test_2(self):
self.assertTrue(True)
if __name__ == '__main__':
testSuite = unittest.TestSuite()
testSuite.addTest(TestMyCode('test_1'))
runner=unittest.TextTestRunner()
runner.run(testSuite)
Output:
------------------------------------------------------------
Ran 1 test in 0.000s
OK

Function is not called using mock.patch

I am trying to test the Class BluetoothClient which connects to a BluetoothSocket. To avoid using real sockets I just want to test that the connect() method from the socket is called with the right parameters. Using mock.patch to replace the imported bluetooth module in my bluetooth_control module doesn't work out like expected.
As I see it, the connect() method is called but the assertion tells me otherwise.
Code:
Unit Under Test (bluetooth_control.py):
import bluetooth
class BluetoothClient(object):
def __init__(self):
self.address="98:D3:31:B2:EF:32"
self.port=1
def establishConnection(self):
self.createSocket()
self.connect()
def createSocket(self):
self.sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
def connect(self):
print "connect: sock="+str(self.sock)
self.sock.connect((self.address, self.port))
Test (bluetooth_control_test.py):
import unittest
import mock
import bluetooth_control
import bluetooth
class TestShelf(unittest.TestCase):
def setUp(self):
unittest.TestCase.setUp(self)
self.bc = bluetooth_control.BluetoothClient()
print "setUp"
def tearDown(self):
self.shelf = None
print "tearDown"
#mock.patch('bluetooth_control.bluetooth')
def testEstablishConnection(self,mock_bluetooth):
self.bc.establishConnection()
print "testEstablishConnection sock="+str(self.bc.sock)
mock_bluetooth.connect().assert_called_with(self.bc.sock,("98:D3:31:B2:EF:32",1))
if __name__ == "__main__":
unittest.main()
Output:
setUp
connect: sock=<MagicMock name='bluetooth.BluetoothSocket()' id='140433322111504'>
testEstablishConnection sock=<MagicMock name='bluetooth.BluetoothSocket()' id='140433322111504'>
FtearDown
======================================================================
FAIL: testEstablishConnection (__main__.TestShelf)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/mock.py", line 1201, in patched
return func(*args, **keywargs)
File "bluetooth_control_test.py", line 21, in testEstablishConnection
mock_bluetooth.connect().assert_called_with(self.bc.sock,("98:D3:31:B2:EF:32",1))
File "/usr/lib/python2.7/site-packages/mock.py", line 831, in assert_called_with
raise AssertionError('Expected call: %s\nNot called' % (expected,))
AssertionError: Expected call: mock(<MagicMock name='bluetooth.BluetoothSocket()' id='140433322111504'>, ('98:D3:31:B2:EF:32', 1))
Not called
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
After looking at the problem again two days later I found the stupid mistakes I made. I had to patch the actual method and remove the falsely added brackets at the assertion.
I am not going to delete this question so that maybe it will help someone to avoid these mistakes.
Test
import unittest
import mock
import bluetooth_control
import bluetooth
class TestShelf(unittest.TestCase):
def setUp(self):
unittest.TestCase.setUp(self)
self.bc = bluetooth_control.BluetoothClient()
print "setUp"
def tearDown(self):
self.shelf = None
print "tearDown"
#mock.patch('bluetooth_control.bluetooth.BluetoothSocket.connect')
def testEstablishConnection(self,mock_connect):
self.bc.establishConnection()
print "testEstablishConnection sock="+str(self.bc.sock)
mock_connect.assert_called_with(("98:D3:31:B2:EF:32",1))
if __name__ == "__main__":
unittest.main()

Running unittest.main() from a module?

I wrote a little function that dynamically defines unittest.TestCase classes (trivial version below).
When I moved it out of the same source file into its own module, I can't figure out how to get unittest to discover the new classes. Calling unittest.main() from either file doesn't execute any tests.
factory.py:
import unittest
_testnum = 0
def test_factory(a, b):
global _testnum
testname = 'dyntest' + str(_testnum)
globals()[testname] = type(testname, (unittest.TestCase,), {'testme': lambda self: self.assertEqual(a, b)})
_testnum += 1
def finish():
unittest.main()
someotherfile.py:
from factory import test_factory, finish
test_factory(1, 1)
test_factory(1, 2)
if __name__ == '__main__':
finish()
Output:
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
So it doesn't execute any tests.
Note that keeping it all in the same file works as expected:
import unittest
_testnum = 0
def test_factory(a, b):
global _testnum
testname = 'dyntest' + str(_testnum)
globals()[testname] = type(testname, (unittest.TestCase,), {'testme': lambda self: self.assertEqual(a, b)})
_testnum += 1
test_factory(1, 1)
test_factory(1, 2)
if __name__ == '__main__':
unittest.main()
Output (as expected):
.F
======================================================================
FAIL: testme (__main__.dyntest1)
----------------------------------------------------------------------
Traceback (most recent call last):
File "partb.py", line 11, in <lambda>
globals()[testname] = type(testname, (unittest.TestCase,), {'testme': lambda self: self.assertEqual(a, b)})
AssertionError: 1 != 2
----------------------------------------------------------------------
Ran 2 tests in 0.008s
FAILED (failures=1)
How I use my test_factory() function such that I can execute all of the TestCase objects it defines from a separate source file?
The general idea (what unittest.main does for you) is:
suite = unittest.TestLoader().loadTestsFromTestCase(SomeTestCase)
unittest.TextTestRunner(verbosity=2).run(suite)
as per http://docs.python.org/library/unittest.html?highlight=unittest#module-unittest . Your test cases are hidden in globals() by the test_factory function, so just do a dir(), find the globals that are instances of unittest.TestCase (or ones with names starting with 'dyntest', etc), and just build your suite that way and run it.
By default, unittest.main() looks for unit TestCase objects in the main module. The test_factory creates the TestCase objects in its own module. That's why moving it outside of the main module causes the behavior you see.
Try:
def finish():
unittest.main(module=__name__)

Categories