Introduction to Unit Testing in Python
Unit Testing in Python is a way of ascertaining whether a software unit performs the intended functionality in the way it is designed. The software unit may be a module or function or an interface with another module. This testing is done mostly at the developer’s level for the code he develops before it is passed on to the next level of integrated testing. Python facilitates developers to create test cases covering all possible scenarios in their program during real-time execution and document all the test cases and their results. This will automate the testing process and enable developers to do the testing within a short period of time any number of times.
How does Unit Testing work in Python?
Upon completing a unit of code in Python, the developer is supposed to test the coding unit to ensure that:
- There is no bug in the program and it works well for all possible test conditions correctly.
- It takes the inputs correctly from upstream software units and pass on the results to the downstream units properly.
Python Developers can resort to manual testing methods to verify the code but it:
- Is a time-consuming task.
- Leaves fatigue.
- Do not document the test data and results in a structured way.
- Is not repeatable and can make maintenance tedious work.
Hence Python developers will have to create scripts that can be used in future testing during the maintenance of the program. Python offers a unit testing framework unit test for the developers to automate the testing process.
Various Test Cases with Examples
Given below are the various test cases with examples:
1. Using simple python code
Assuming a developer is creating a software unit to determine the square root of a number and the code for this function,
Code:
# function to compute square root of a number
import math # importing Mathematics module
def square_root(l): # Function beginning
return math.sqrt(l) # Returning results
A simple way of manual testing will be to write a code.
print ("square root of 64 ",square_root(64))
Output:
Another test case is:
print ("square root of 64A ",square_root("64A"))
Failed result is:
Here the user will have to preserve test codes for future testing.
2. Using assert command in python
Assert command compares the result with the given value and return an error if the condition is not met.
Code:
assert square_root(64) == 8 , "should be 8" #Code will not result in any error
assert square_root(64) == 7 , "should be 8" #will return error condition
Output:
The developer can code multiple test cases but the execution will stop on the first error.
3. Multiple test cases using assert
Code:
def test_sqrt():
assert square_root(64) == 8 , "should be 8"
assert square_root(81) == 9 , "should be 9"
assert square_root(100) == 10 , "should be 10"
if __name__ == "__main__":
test_sqrt()
print("Everything passed")
All the test cases are put in a python function and they are executed under __name__ == “ __main__” condition. It essentially means that the module is run in standalone mode directly within the code and not imported from an external repository.
Output:
Code:
import math
def square_root(l):
return math.sqrt(l)
def test_sqrt():
assert square_root(64) == 8 , "should be 8"
assert square_root(81) == 9 , "should be 9"
assert square_root(100) == 11 , "should be 10"
if __name__ == "__main__":
test_sqrt()
print("Everything passed")
Output:
Though a little bit of automation with multiple test cases is possible in this method, it does not provide comprehensive test results of how many cases have failed and how many have passed. We can only manage simple cases with this method. Test runners provide a special application for easy execution of test cases and publish a clear result of no of passed and failed cases.
Test Runners in Python
Unit test is an inbuilt test runner within Python.
Unique features of this test runner are:
- Test conditions are coded as methods within a class.
- Allows a variety of assert methods from unittest library as against a simple assert statement in the earlier examples.
Steps:
- Unit test library should be imported.
- A class Testclass should be created inheriting Testcase class from unittest library.
- Add var as the first argument in all the methods in test functions.
- Replace assert with var.asssert.equal method in Testcase class.
- Unittest.main() is the entry point.
Code:
import math
import unittest
def square_root(l):
return math.sqrt(l)
class Testclass(unittest.TestCase):
def test_case1(var):
var.assertEqual(square_root(121), 11, "Should be 11")
def test_case2(var):
var.assertEqual(square_root(144), 12, "Should be 12")
def test_case3(var):
var.assertEqual(square_root(169), 13, "Should be 12")
def test_case4(var):
var.assertEqual(square_root(196), 14, "Should be 12")
def test_case5(var):
var.assertEqual(square_root(225), 15, "Should be 12")
def test_case6(var):
var.assertEqual(square_root(256), 16, "Should be 12")
if __name__ == "__main__":
unittest.main()
Output:
The result is (all the 6 cases are correct):
When the code is changed as:
Code:
import math
import unittest
def square_root(l):
return math.sqrt(l)
class Testclass(unittest.TestCase):
def test_case1(var):
var.assertEqual(square_root(121), 11, "Should be 11")
def test_case2(var):
var.assertEqual(square_root(144), 12, "Should be 12")
def test_case3(var):
var.assertEqual(square_root(169), 13, "Should be 12")
def test_case4(var):
var.assertEqual(square_root(196), 14.3, "Should be 12")
def test_case5(var):
var.assertEqual(square_root(225), 15.2, "Should be 12")
def test_case6(var):
var.assertEqual(square_root(256), 16, "Should be 12")
if __name__ == "__main__":
unittest.main()
Output:
The result (with 2 errors):
Results clearly shows the number of cases tested and no of cases failed.
Other assert methods available in python:
- AssertAlmostEqual: With rounding off at 5th decimal the comparison is done.
- AssertTrue(x): Boolean expression x is true when evaluated.
- AssetFalse(x): Boolean expression x is false when evaluated.
- Assertequal(a,b): a = b
- AssertIn(a,b): a in b
- AssertIs(a,b): a is b
- AssertIsNone(a): a is null
Other test runners:
There are some more test runners apart from the built-in tool unit test.
- Nose is considered to be the extension of the unit test.
- Pytest has backward compatibility with minimal code.
- Hypothesis has a quick start and covers edge cases.
- Mimesis has the ability to generate artificial data that are useful for testing.
- Testify is similar to pytest.
Conclusion
Python provides an extensive facility to carry out unit testing and automate it too for easy maintenance of the code by developers.
Recommended Articles
This is a guide to Unit Testing in Python. Here we discuss the introduction, working, various test cases with examples, and test runners in Python. You may also have a look at the following articles to learn more –
40 Online Courses | 13 Hands-on Projects | 215+ Hours | Verifiable Certificate of Completion
4.8
View Course
Related Courses