Unit testing is a software testing method by which individual units of source code are put under various tests to determine whether they are fit for use. It determines and ascertains the quality of your code.
Generally, when the development process is complete, the developer codes criteria, or the results that are known to be potentially practical and useful, into the test script to verify a particular unit's correctness. During test case execution, various frameworks log tests that fail any criterion and report them in a summary.
The developers are expected to write automated test scripts, which ensures that each and every section or unit meets its design and behaves as expected.
Python Unit Testing
Though writing manual tests for your code is definitely a tedious and time-consuming task, Python's built-in unit testing framework has made life a lot easier.
The unit test framework in Python is called unittest which comes packaged with Python.
Unit testing makes your code future-proof since you anticipate the cases where your code could potentially fail or produce a bug. Though you cannot predict all of the cases, you still address most of them.
A unit could be bucketed into various categories:
An entire module,
An individual function,
A complete interface like a class or a method.
The best ways to write unit tests for your code is to first start with the smallest testable unit your code could possibly have, then move on to other units and see how that smallest unit interacts with other units, this way you could build up a comprehensive unit test for your applications.
Python's unit testing framework was inspired by java's JUnit and has similar features as major unit testing frameworks in other languages. Python's unit testing framework offers variousfeatures, including:
Test automation
Sharing of setup and shutdown code for tests
Aggregating tests into collections
Independence of the tests from the reporting framework
Now let's take an example and understand why you need to have unit testing of your code.
Getting Started with Python unittest
Below, we've outlined the steps you need to use Python's unittest framework
Creating a cube function
Let's write a code to calculate the volume of a cube in Python
defcuboid_volume(l):return(l*l*l)
length =[2,1.1,-2.5,2j,'two']for i inrange(len(length)):print("The volume of cuboid:",cuboid_volume(length[i]))Obsługiwane przez
The volume of cuboid: 8
The volume of cuboid: 1.3310000000000004
The volume of cuboid: -15.625
The volume of cuboid: (-0-8j)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-67e1c37a435f> in <module>
1 for i in range(len(length)):
----> 2 print ("The volume of cuboid:",cuboid_volume(length[i]))
<ipython-input-2-f50464fd88da> in cuboid_volume(l)
1 def cuboid_volume(l):
----> 2 return (l*l*l)
TypeError: can't multiply sequence by non-int of type 'str'Obsługiwane przez
Result analysis
The above output should give you some intuition about the importance of having a unit test in place for your code. Now there are three things that are certainly incorrect in the above code:
First, the volume of cuboid being negative,
Second, the volume of the cuboid is a complex number,
Finally, the code resulting in a TypeError since you cannot multiply a string, which is a non-int.
The third problem thankfully resulted in an error while the first & second still succeeded even though the volume of the cuboid cannot be negative and a complex number.
Unit tests are usually written as a separate code in a different file, and there could be different naming conventions that you could follow. You could either write the name of the unit test file as the name of the code/unit + test separated by an underscore or test + name of the code/unit separated by an underscore.
For example, let's say the above code file name is cuboid_volume.py, then your unit test code name could be cuboid_volume_test.py
Without any further ado, let's write the unit test for the above code.
Using assertAlmostEqual
First, let's create a python file with the name volume_cuboid.py, which will have the code for calculating the volume and second with the name test_volume_cuboid.py, which will have the unit testing code.
importunittest
The TestCuboid class inherits the unittest module, and in this class, you would define various methods that you would want your unit test should check with your function cuboid_volume.
The first function you will define is test_volume, which will check whether the output your cuboid_volume gives is equal to what you expect. To achieve this, you will make use of the assertAlmostEqual method.
F
======================================================================
FAIL: test_volume (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 15, in test_volume
self.assertAlmostEqual(cuboid_volume(5.5),0)
AssertionError: 166.375 != 0 within 7 places (166.375 difference)
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)Obsługiwane przez
Well, from the above output, you can observe that the last assert statement resulted in an AssertionError, hence a unit test failure. Python's unit test module shows you the reason for the failure, along with the number of failures your code has.
Using assertRaises
Now let's explore another assert method, i.e., assertRaises, which will help you in finding out whether your function cuboid_volume handles the input values correctly.
Let's say you want to test whether your function cuboid_volume handles the class or type of input, for example, if you pass a string as an input, will it handle that input either as an exception or with an if condition since the length of the cuboid can never be a string.
F.
======================================================================
FAIL: test_input_value (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 17, in test_input_value
self.assertRaises(TypeError, cuboid_volume, True)
AssertionError: TypeError not raised by cuboid_volume
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)Obsługiwane przez
Great! So from the above output, it is evident that your code volume_cuboid.py doesn't take care of the input being passed to it properly.
Modifying the cube function
Let's add a condition in the volume_cuboid.py to check whether the input or length of the cuboid is a boolean or a string and raise an error.
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OKObsługiwane przez
Running the Python Testing Script in Jupyter lab
Let's now run the testing script within the jupyter lab. To achieve this, you would first define the testing script in the jupyter lab, as shown below.
# -*- coding: utf-8 -*-"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""from volume_cuboid import*import unittest
classTestCuboid(unittest.TestCase):deftest_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)deftest_input_value(self):
self.assertRaises(TypeError, cuboid_volume,True)Obsługiwane przez
Then, you will use the unittest.main() method to run the testing script, you can pass several arguments to the below method, out of which one is verbosity level.
Let's experiment with different verbosity levels and see how it changes the output description.
Verbosity 0
unittest.main(argv=[''],verbosity=0, exit=False)
Output:
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
<unittest.main.TestProgramat0x1de02774348>Obsługiwane przez
Verbosity 1
unittest.main(argv=[''],verbosity=1, exit=False)
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgramat0x1de027a1cc8>Obsługiwane przez
Verbosity 2
unittest.main(argv=[''],verbosity=2, exit=False)
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgramat0x1de027a8308>Obsługiwane przez
Visualizing the AssertionError
Lastly, let's modify the final assertAlmostEqual in the test_volume method and analyze how the verbosity level 2 will show the method failure.
# -*- coding: utf-8 -*-"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""from volume_cuboid import*import unittest
classTestCuboid(unittest.TestCase):deftest_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)deftest_input_value(self):
self.assertRaises(TypeError, cuboid_volume,True)
unittest.main(argv=[''],verbosity=2, exit=False)Obsługiwane przez
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... FAIL
======================================================================
FAIL: test_volume (__main__.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-28-46ad33b909ee>", line 14, in test_volume
self.assertAlmostEqual(cuboid_volume(0),1)
AssertionError: 0 != 1 within 7 places (1 difference)
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=1)
<unittest.main.TestProgramat0x1de027b5448>Obsługiwane przez
Summary
From the above outputs, the following conclusions can be made:
Verbosity level 0 just shows how many tests were run, i.e., 2 tests along with the time it took to run them,
Verbosity level 1 add two dots .. which signifies two tests were executed,
Verbosity level 2 shows the detailed method names which were run along with their state OK or FAIL.
Available unittest Assert Methods
There are a lot of assert methods in the unit test module of Python, which could be leveraged for your testing purposes.
You could also learn about them with the help of the Pydoc module, which is similar to a help function in Python. A demonstration of how you could use the Pydoc module to read about the assertCountEqual method's documentation is shown below.
Help on function assertCountEqual in unittest.TestCase:
unittest.TestCase.assertCountEqual = assertCountEqual(self, first, second, msg=None)
An unordered sequence comparison asserting that the same elements,
regardless of order. If the same element occurs more than once,
it verifies that the elements occur the same number of times.
self.assertEqual(Counter(list(first)),
Counter(list(second)))
Example:
- [0, 1, 1] and [1, 0, 1] compare equal.
- [0, 0, 1] and [0, 1] compare unequal.Obsługiwane przez
Conclusion
This tutorial was a basic introduction to unit testing in python and its importance as a developer. One good exercise for you would be to write a unit test module for any of your past projects. This will give you a good hands-on experience with writing unit tests. Also, try exploring the remaining Assert methods. You can read more about unit testing with ourPytest tutorial.
As a certified data scientist, I am passionate about leveraging cutting-edge technology to create innovative machine learning applications. With a strong background in speech recognition, data analysis and reporting, MLOps, conversational AI, and NLP, I have honed my skills in developing intelligent systems that can make a real impact. In addition to my technical expertise, I am also a skilled communicator with a talent for distilling complex concepts into clear and concise language. As a result, I have become a sought-after blogger on data science, sharing my insights and experiences with a growing community of fellow data professionals. Currently, I am focusing on content creation and editing, working with large language models to develop powerful and engaging content that can help businesses and individuals alike make the most of their data.
Unit testing is a software testing method by which individual units of source code are put under various tests to determine whether they are fit for use. It determines and ascertains the quality of your code.
Generally, when the development process is complete, the developer codes criteria, or the results that are known to be potentially practical and useful, into the test script to verify a particular unit's correctness. During test case execution, various frameworks log tests that fail any criterion and report them in a summary.
The developers are expected to write automated test scripts, which ensures that each and every section or unit meets its design and behaves as expected.
Python Unit Testing
Though writing manual tests for your code is definitely a tedious and time-consuming task, Python's built-in unit testing framework has made life a lot easier.
The unit test framework in Python is called
unittestwhich comes packaged with Python.Unit testing makes your code future-proof since you anticipate the cases where your code could potentially fail or produce a bug. Though you cannot predict all of the cases, you still address most of them.
A unit could be bucketed into various categories:
The best ways to write unit tests for your code is to first start with the smallest testable unit your code could possibly have, then move on to other units and see how that smallest unit interacts with other units, this way you could build up a comprehensive unit test for your applications.
Python's unit testing framework was inspired by java's
JUnitand has similar features as major unit testing frameworks in other languages. Python's unit testing framework offers various features, including:Now let's take an example and understand why you need to have unit testing of your code.
Getting Started with Python unittest
Below, we've outlined the steps you need to use Python's
unittestframeworkCreating a cube function
Let's write a code to calculate the volume of a cube in Python
Result analysis
The above output should give you some intuition about the importance of having a unit test in place for your code. Now there are three things that are certainly incorrect in the above code:
TypeErrorsince you cannot multiply a string, which is a non-int.The third problem thankfully resulted in an error while the first & second still succeeded even though the volume of the cuboid cannot be negative and a complex number.
Unit tests are usually written as a separate code in a different file, and there could be different naming conventions that you could follow. You could either write the name of the unit test file as the
name of the code/unit + testseparated by an underscore ortest + name of the code/unitseparated by an underscore.For example, let's say the above code file name is
cuboid_volume.py, then your unit test code name could becuboid_volume_test.pyWithout any further ado, let's write the unit test for the above code.
Using assertAlmostEqual
First, let's create a python file with the name
volume_cuboid.py, which will have the code for calculating the volume and second with the nametest_volume_cuboid.py, which will have the unit testing code.import unittest
The
TestCuboidclass inherits theunittestmodule, and in this class, you would define various methods that you would want your unit test should check with your functioncuboid_volume.The first function you will define is
test_volume, which will check whether the output yourcuboid_volumegives is equal to what you expect. To achieve this, you will make use of theassertAlmostEqualmethod.Test 1
Let's run the above script. You would run the
unittestmodule as a script by specifying-mwhile running it.Output:
Great! So you got your first unit test code working.
The test ran successfully and returned,
OK, which means the cuboid_volume function works as you would expect it too.Test 2
Let's see what happens when one of the
assertAlmostEqualmethods fails.Notice that the last assert statement has been modified.
Output:
Well, from the above output, you can observe that the last assert statement resulted in an
AssertionError, hence a unit test failure. Python's unit test module shows you the reason for the failure, along with the number of failures your code has.Using assertRaises
Now let's explore another assert method, i.e.,
assertRaises, which will help you in finding out whether your functioncuboid_volumehandles the input values correctly.Let's say you want to test whether your function
cuboid_volumehandles the class or type of input, for example, if you pass a string as an input, will it handle that input either as an exception or with an if condition since the length of the cuboid can never be a string.Output:
Great! So from the above output, it is evident that your code
volume_cuboid.pydoesn't take care of the input being passed to it properly.Modifying the cube function
Let's add a condition in the
volume_cuboid.pyto check whether the input or length of the cuboid is a boolean or a string and raise an error.Output:
Running the Python Testing Script in Jupyter lab
Let's now run the testing script within the jupyter lab. To achieve this, you would first define the testing script in the jupyter lab, as shown below.
Then, you will use the
unittest.main()method to run the testing script, you can pass several arguments to the below method, out of which one isverbosity level.Let's experiment with different verbosity levels and see how it changes the output description.
Verbosity 0
Verbosity 1
Verbosity 2
Visualizing the AssertionError
Lastly, let's modify the final
assertAlmostEqualin thetest_volumemethod and analyze how the verbosity level 2 will show the method failure.Output:
Summary
From the above outputs, the following conclusions can be made:
OKorFAIL.Available unittest Assert Methods
There are a lot of assert methods in the unit test module of Python, which could be leveraged for your testing purposes.
Commonly used assert methods
Source: unittest documentation
Production checks
By using the following methods, you can check production of exceptions, warnings, and log messages.
Source: unittest documentation
Task-specific methods
Source: unittest documentation
To know in detail about the
assertmethods, check out Python's official documentation.You could also learn about them with the help of the
Pydocmodule, which is similar to ahelpfunction in Python. A demonstration of how you could use the Pydoc module to read about theassertCountEqualmethod's documentation is shown below.Output:
Conclusion
This tutorial was a basic introduction to unit testing in python and its importance as a developer. One good exercise for you would be to write a unit test module for any of your past projects. This will give you a good hands-on experience with writing unit tests. Also, try exploring the remaining Assert methods. You can read more about unit testing with our Pytest tutorial.
If you are just getting started in Python and would like to learn more, take our Introduction to Data Science in Python course.