Test-driven development
ALXSE Guided Summary - 0x07. Python - Test-driven development - unittests
Test-driven development
TDD is a software development approach that involves writing tests before writing the code that implements a feature. It helps to ensure that code is thoroughly tested and meets the requirements of the software specifications before it is written. By writing tests first, developers can catch bugs early in the development process and ensure that they have a clear understanding of what the code is supposed to do. TDD is widely used in software development organizations of all sizes and is often associated with agile software development methodologies.
Doctest:
Doctest
is a lightweight testing framework that is easy to use and requires no external tools or dependencies. It is often used for testing small, self-contained functions and modules. However, it may not be suitable for more complex testing scenarios or for testing code that interacts with external resources, such as databases or web services.
the example is about using doctests
with a Calculator class that has methods for adding, subtracting, multiplying, and dividing numbers. The doctests are included in the docstrings of each method using the >>>
prompt.
The >>>
prompt is used in doctests to indicate an example of how to use a function or method. After the >>>
prompt, you would typically include some code that demonstrates how to use the function or method, followed by the expected output of that code. Here's an example:
def add(a, b):
"""
Returns the sum of two numbers.
>>> add(2, 3)
5
"""
To run the doctests, we include an if __name__ == "__main__":
block that runs the testmod() function from the doctest module
. This function checks that the actual output of each example in the docstrings matches the expected output.
To use the Calculator
class, we create an instance of the class and call its methods using the dot notation.
If we want to see the output of the tests, we can include the -v
flag when running the doctest
command.
python3 -m doctest -v doctest_ex.py
Unit Tests in Python:
Testing technique in which individual units or components of a software application are tested in isolation from the rest of the application to ensure that they are working correctly. In Python, the built-in unittest
module provides a framework for writing and running unit tests.
Here's an example of how to write a unit test in Python using the unittest
module:
In this example, we define a add()
function that takes two numbers as input and returns their sum. We also define a TestAdd
class that inherits from the unittest.TestCase
class.
Inside the TestAdd
class, we define several test methods that start with the word test
. Each test method uses the assertEqual()
method to compare the actual output of the add()
function with the expected output. If the actual output does not match the expected output, the test will fail.
At the bottom of the file, we include an if __name__ == '__main__':
block that calls the unittest.main()
function. This function discovers and runs all of the test methods in the file.

unittest
module will automatically discover and run the test methods in the TestAdd
class. 
unittest
will print an error message indicating which test failed and what the actual output was.Best Practice:
Tips:
Docstring must be before import statements.
If you are not allowed to import any module ex. :
import unittest, y
ou will need to usedoctest
Isolate tests in a separate
dir/file
:what should I write in tests/file.txt:
you should write a series of doctests to test the behavior of the function. Doctests are written as examples in the docstring of the function being tested, and they should demonstrate how the function behaves in different scenarios.
example:
>>> add(2, 3)
5
>>> add('2', 3)
Traceback (most recent call last)
TypeError: num1 must be an integer or float
Run:
$ python -m doctest -v tests/file.txt
In your isolated test file you need to import function to be tested in same manner :
In Python, you can use the
__import__()
function to import a module by name as a Python object. In this case, the__import__('fileName')
statement imports thefileName.py
module as a Python object.To access the function defined in
fileName.py
, we can use the dot notation to access the function as an attribute of the imported module:__import__('fileName').functionName
Example:
>>> add_nums = __import__('0-add').add_nums
>>> add_nums (1, 2)
3
In Python, the
__doc__
attribute is used to access the docstring of a module, class, function, or method.
To print number of lines of docstring of a module and prints its docstring, which contains a description of the module and its functions. By counting the number of lines in the docstring using the
wc
command, you can get an idea of how well-documented the module is.Example: to have 5 Lines
"""
This is the add_nums module.
It contains a function for adding two numbers.
"""
The docstring has five lines, even though it contains only three sentences. Here is a breakdown of the lines in the docstring:
The first line is a string literal that starts with three double quotes (
"""
). This marks the beginning of the docstring.The second line contains the text "This is the add_nums module." This is the first sentence of the docstring.
The third line is a blank line. According to PEP 257, which provides guidelines for writing docstrings, it is recommended to use a blank line to separate the summary line from the rest of the docstring.
The fourth line contains the text "It contains a function for adding two numbers." This is the second sentence of the docstring.
The fifth line is another string literal that ends with three double quotes (
"""
). This marks the end of the docstring.Note :
python3 -m doctest -v ./testsFolder/file.txt
gives tests runs in details
By running the
python3 -c 'print(__import__("my_module").__doc__)'
command, you can quickly check whether a module has a docstring, and if so, what it contains. If the docstring is missing or incomplete, you can add or improve it to make the module more usable and maintainable.By running the
python3 -c 'print(__import__("my_module").my_function.__doc__)'
command, you can quickly check do the same but for a function.
Edge Cases:
Finding edge cases involves identifying scenarios or inputs that are at the limits or extremes of what is expected or allowed by the program. Edge cases are important to test because they can often reveal bugs or unexpected behavior in the program that might not be caught by more typical test cases.
Here are some strategies for finding edge cases:
Look at the input requirements: Identify the constraints or requirements for the input parameters of the program or function and try to find values that are at the limits of those constraints. For example, if a function expects a positive integer, test it with the smallest possible value (0 or 1) and the largest possible value (the maximum value allowed by the data type).
Consider boundary conditions: Identify any boundaries or limits that the program or function might encounter, such as the beginning or end of a list or array, or the minimum or maximum value of a data type. Test the program with inputs that are at or near these boundaries to see how it behaves.
Think about unexpected inputs: Consider inputs that the program might not expect or that are not explicitly defined in the requirements. For example, what happens if the input is a negative number, a string instead of an integer, or an empty list? Test the program with these unexpected inputs to see how it handles them.
Test for unusual or exceptional conditions: Consider scenarios that are unlikely to occur but could still happen, such as network errors, file system errors, or out-of-memory conditions. Test the program with these unusual conditions to see how it handles them.
Resources:
This is an updating content, some tips will be added here, stay tuned…
If you have any questions please add it in comments section :