Unittest example not working - python

I'm just learning about python and unittests in particular.
I'm trying to follow the following simple example where the function being tested is:
def get_formatted_name(first, last):
"""Generate a neatly formatted name"""
full_name = first + ' ' + last
return full_name.title()
and the test code is:
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Tests for 'name_function.py'"""
def test_first_last_name(self):
"""Do names liike 'Janis Joplin' work """
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
unittest.main()
According to the example this should run fine and report that the test ran successfully.
However I get the following errors:
EE
======================================================================
ERROR: test_name_function (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute 'test_name_function'
======================================================================
ERROR: true (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute 'true'
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=2)
Process finished with exit code 1
Unfortunately I have no idea what is going wrong!

As per the documentation you would need to add the following code. That way it'll run as the main module rather than anything else. You can see the example here.
if __name__ == '__main__':
unittest.main()

Related

Creating a Unit testcase Class within a function not running testcases

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)

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

Unit test in Python not running

I'm trying to test my code with unit tests, but when I try to run it it just says
Finding files... done.
Importing test modules ... done.
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Why isn't it working?
from Graph import Graph
import unittest
class GraphTest:
def setUp(self):
self.graph = Graph()
for i in range(5):
self.graph.addNode(i,"Node"+i)
self.graph.addEdge(1,5,"Edge1,5")
self.graph.addEdge(5,1,"Edge5,1")
self.graph.addEdge(3,2,"Edge3,2")
def test_Connected(self):
self.assertTrue(self.graph.isConnected(1,5))
self.assertTrue(self.graph.isConnected(5,1))
self.assertTrue(self.graph.isConnected(3,2))
self.assertFalse(self.graph.isConnected(2,3))
self.assertFalse(self.graph.isConnected(1,4))
if __name__ == '__main__':
unittest.main()
You should make your GraphTest a subclass of unittest.TestCase

AttributeError: None does not have the attribute 'print'

So I am practicing some unit test and I am trying to check for an output that is within a For Loop. Here is my run code
def main():
for i in range(100):
print("Argh!")
Pretty basic, now here is my test code.
import unittest
from unittest import mock # possibly "from unittest import mock" depending on version.
from RunFile import main
class TestMain(unittest.TestCase):
def test_main(self):
with mock.patch.object(main(), 'print') as mock_print:
main()
expected_calls = [mock.call('Argh!') for _ in range(100)]
mock_print.assert_has_calls(expected_calls)
if __name__ == '__main__':
unittest.main()
Here is the error message I get back. I'm not to sure how to resolve this.
UPDATED: Here is the full trace back
======================================================================
ERROR: test_main (__main__.TestMain)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:/Users/jsalce/Documents/Testsuites/IfStatements/Testsuite.py", line 9, in test_main
with mock.patch.object(RunFile, 'print') as mock_print:
File "C:\Python33\lib\unittest\mock.py", line 1148, in __enter__
original, local = self.get_original()
File "C:\Python33\lib\unittest\mock.py", line 1122, in get_original
"%s does not have the attribute %r" % (target, name)
AttributeError: <module 'RunFile' from 'C:\\Users\\jsalce\\Documents\\Testsuites\\IfStatements\\RunFile.py'> does not have the attribute 'print'
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
Thank you all in advance!
Generally speaking, for mock.patch.object, you want to patch something that you have an easy handle on -- e.g. a module or a class. Usually, you need to patch something that is one level above what you want to replace. For example if you want to patch the foo function in module bar, then you need mock.patch.object(bar, 'foo').
In your case, technically, print is a builtin, but you can patch it on the module where you're using it. This will add a RunFile.print "method" (which is actually a mock) that you can test assertions against. Apparently, since print doesn't actually exist on the module, we need to add create=True to tell mock to create RunFile.print since it doesn't already exist. With that in mind, I'd re-write the unittest as:
import RunFile
class TestMain(unittest.TestCase):
def test_main(self):
with mock.patch.object(RunFile, 'print', create=True) as mock_print:
RunFile.main()
expected_calls = [mock.call('Argh!') for _ in range(100)]
mock_print.assert_has_calls(expected_calls)
if __name__ == '__main__':
unittest.main()

How to get the exception thrown in unittest

I have my own exceptions and i want to test farther fields in the ex other then the message.
Reading this thread i tried the idea of using a context. I wrote this generic function
def test_runtime_error(test, exception_type, message, display_parameter, path, callable_obj, *args):
pdb.set_trace()
with test.assertRaises(exception_type) as cx:
callable_obj(*args)
ex = cx.exception
test.assertEqual(ex.message,message)
test.assertEqual(ex.display_parameter,display_parameter)
test.assertEqual(ex.path,path)
The path and display_parameter are my own specific fields. I'm not inventing the wheel here, i took most of it from the source.
I'm using it like that
class ExceptionsTest(unittest.TestCase):
def test_something(self):
data = {"name" : "A"}
obj = MyModel.objects.get(pk=1)
test_runtime_error(self,CustomException, 'message', 'A', [], obj.create, data)
The arguments are passed correctly into the callable_obj. the function raises the expected exception. but right after the execution of callable_obj the function breaks and the exception is not fetched. BTW, when i ran the same code in the test it self it worked fine.
Whats wrong here ?
The issue here appears to be this line:
pdb.set_trace()
If you leave it in, but don't have import pdb, the code below will fail with:
E
======================================================================
ERROR: testRaises (__main__.ExceptionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./except.py", line 22, in testRaises
self.verifyComplexException(MyException, 'asdf', RaiseException, 'asdf')
File "./except.py", line 14, in verifyComplexException
pdb.set_trace()
NameError: global name 'pdb' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
which matches your description. If you do add the import pdb line, it will drop into the debugger, which is a completely different behavior that cannot be confused for the exit with E or exit with F status, so it can't be that.
Here's a complete example based on this idea which works as intended (licensed under Apache 2.0; see my repo):
import unittest
class MyException(Exception):
def __init__(self, message):
self.message = message
def RaiseException(message):
raise MyException(message)
class ExceptionTest(unittest.TestCase):
def verifyComplexException(self, exception_class, message, callable, *args):
with self.assertRaises(exception_class) as cm:
callable(*args)
exception = cm.exception
self.assertEqual(exception.message, message)
def testRaises(self):
self.verifyComplexException(MyException, 'asdf', RaiseException, 'asdf')
if __name__ == '__main__':
unittest.main()

Categories