Beginner’s guide for Testing in Python
There are many ways to test your code in python. Given below are a few comparative studies to use the best testing method in python.
Automated vs. Manual Testing
When the user checks features and experiments with them without any plan when an application runs for the first time, that is called manual testing, also known as exploratory testing.
To begin with a manual test, you need to have a complete set of manual tests. i.e. making a list of all the features the application has the different types of input it can accept, and the expected results. When the code is changed, one has to go through every single item on that list and check it.
Yes, it is very monotonous and could be a lengthy procedure. Thus, this is where automated testing is different from manual testing.
The execution of your plan to test the application is known as automated testing. It mainly includes the following:
- The piece of the application you want to test,
- The order in which you want to test them, and
- The expected results.
Python already comes with a set of tools and libraries to help one create automated tests by a script for one’s application rather than a human.
Unit Tests vs. Integration Tests
To understand Integration testing let's consider a scenario where a person is testing whether a car headlight is working or not. To start the test, you would turn on the lights (known as the test step) and then go out of the car or ask a friend to check if the headlights are on (known as the test assertion). Testing multiple components like these (separately) is known as integration testing.
Consider all the things that have to work correctly so that a simple task gives the right result. These components (classes, functions, and modules you’ve written) are parts to your application.
What happens if integration testing does not give the right result? It would become difficult to diagnose where the issue is, without being able to understand which part of the system is failing. What if the lights of the car did not turn on? It could be because the bulb might have broken, the battery might have discharged, the alternator could also be a reason, or maybe the car’s computer is failing and so on.
If one has a modern & advanced car, it will tell the owner when the light bulbs go off. It is capable of doing this because of using a form of unit test.
A unit test is a smaller test. It is that test which checks that a single component operates in the right way. A unit test helps one to isolate the broken in the application and fix it faster.
Overview of both the tests is:
1. Integration test checks those components in an application that operates with each other.
2. A unit test checks little components in an application.
HOW TO WRITE TEST CODES?
Both integration tests and unit tests can be written in Python.
A correct example for Unit Test:
Now, to write a unit test for the built-in function sum(), one will have to check the output of sum() against a known output.
For example, this is how a person can check that the sum() of the numbers (4, 5, 6) equals 15:
>>> assert sum([4, 5, 6]) == 15, "Should be 15"
This will give no output on the REPL because the values entered are correct.
An error generating example for unit Test:
If the result from sum() would have been incorrect, this will fail with an AssertionError and the message "Should be 15".
This example shows the AssertionError:
>>> assert sum([3, 3, 3]) == 15, "Should be 15"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Should be 15
In the REPL, the raised AssertionError is displayed, because the result of sum() does not match 15.
To test this function in the command line, this can be done:
put this code into a new Python file called test_sum.py and execute it again:
assert sum([4, 5, 6]) == 15, "Should be 15"
if __name__ == "__main__":
Now the above code has a written test case, an assertion, and an entry point (the command line). Execute this at the command line:
$ python test_sum.py
Voila, the successful result is displayed, Everything passed.
In Python, sum() accepts any iterable as its first argument. You tested with a list. Now as a part of exploring python possibilities, test sum() with a tuple as well, on your own.
Writing tests in this way is okay for a simple check, but what if more than one fails to occur in an application? This is where test runners play a major role.
The test runner is a marvellous application designed for running tests, checking the outputs, and giving the user the tools for debugging and diagnosing tests & applications.
Choosing a Test Runner
There are numerous test runners available for Python. But the one built into the Python standard library is called unittest.
The principles of unittest are very easily portable to other frameworks. The three most popular test runners are:
- nose or nose2
You must choose the best test runner as per your requirements and level of experience.
unittest has been built into the Python standard library since version 2.1. It can be seen in commercial Python applications and open-source projects. It contains both: a testing framework and also a test runner but it has its important requirements for writing and executing tests.
Requirements of unittest:
unittest requires that:
- users put their tests into classes as methods
- users use a series of special assertion methods in the unittest.TestCase class instead of the built-in assert statement
To use the previous example to a unittest test case, one would have to:
1. Import unittest from the standard library
2. Create a class called TestSum that inherits from the TestCase class
3. Convert the test functions into methods by adding self as the first argument
4. Change the assertions to use the self.assertEqual() method on the TestCase class
5. Change the command-line entry point to call unittest.main()
Example of unittest code:
A new file test_sum_unittest.py can be created with the following code:
self.assertEqual(sum([4, 5, 6]), 15, "Should be 15")
self.assertEqual(sum((3, 3, 3)), 15, "Should be 15")
if __name__ == '__main__':
If this code is executed at the command line, the user will be able to see one success (indicated with ‘.’) and one failure (indicated with ‘F’)
This process of execution of two tests was done with the unittest test runner.
Note: Be careful In Python 2.7 and below, unittest is called unittest2
Over time, as one writes hundreds or even thousands of tests for an application, it becomes increasingly hard to understand and use the output from unittest.
The nose is compatible with any tests written using the unittest framework and can be used as a drop-in replacement for the unittest test runner.
If one is starting from scratch, it is recommended that that user uses nose2 instead of the nose.
How to get started with nose2:
install nose2 from PyPI ,
and execute it on the command line.
nose2 will try to discover all test scripts named test*.py and test cases inheriting from unittest.TestCase in the current directory:
$ pip install nose2
$ python -m nose2
====================================================================== #here the ‘.’ And ‘F’ stands for the same meaning.
This way, the test that was created in test_sum_unittest.py is executed from the nose2 test runner. nose2 offers many command-line flags for filtering the tests that are executed.
pytest supports execution of unittest test cases. The real advantage of pytest comes by writing pytest test cases. pytest test cases are a series of functions in a Python file starting with the name test_.
- Support for the built-in assert statement instead of using special self.assert*() methods
- Support for filtering for test cases
- Ability to rerun from the last failing test
- An ecosystem of hundreds of plugins to extend the functionality
Example of pytest code:
Writing the TestSum test case example for pytest would look like this:
assert sum([4, 5, 6]) == 15, "Should be 15"
assert sum((3, 3, 3)) == 15, "Should be 15"
With the knowledge of different Python Testing methods and basics of Test Runner, one can perform a few basic tests in python. Try and execute these codes and explore the applications to understand deeply about testing in python.