Python tutorials > Testing > Unit Testing > How to organize tests?
How to organize tests?
Basic Structure: The Test Directory
tests. This directory should reside at the top level of your project. Within the tests directory, you'll mirror the structure of your source code. For example, if you have a module named my_module.py, you'd create a corresponding test file named test_my_module.py within the tests directory.
Mirroring Source Code Structure
my_project/
my_module/
module_a.py
module_b.py
main.py
Your tests directory should mirror this:tests/
my_module/
test_module_a.py
test_module_b.py
test_main.py
Example: Simple Project Structure
calculator.py module and a corresponding test_calculator.py. The TestCalculator class within test_calculator.py contains individual test methods for the add and subtract functions.
# my_project/calculator.py
def add(x, y):
return x + y
def subtract(x, y):
return x - y
# tests/test_calculator.py
import unittest
from my_project.calculator import add, subtract
class TestCalculator(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
def test_subtract(self):
self.assertEqual(subtract(5, 2), 3)
self.assertEqual(subtract(0, 0), 0)
if __name__ == '__main__':
unittest.main()
Using setUp and tearDown
setUp and tearDown methods are extremely useful for setting up preconditions before each test and cleaning up afterwards. setUp is executed before each test method, allowing you to initialize objects or resources. tearDown is executed after each test method, providing an opportunity to release resources or reset the environment. This ensures that each test runs in isolation. In this example a class MyClass is instantiated using the setUp method, thus self.my_instance is instantiated before each test. The tearDown method sets to None the instance to clean up resources.
import unittest
class MyClass:
def __init__(self):
self.data = []
def append_item(self, item):
self.data.append(item)
class TestMyClass(unittest.TestCase):
def setUp(self):
# Initialize the MyClass instance before each test
self.my_instance = MyClass()
def tearDown(self):
# Clean up resources after each test (optional)
self.my_instance = None
def test_append_item(self):
self.my_instance.append_item(5)
self.assertEqual(len(self.my_instance.data), 1)
self.assertEqual(self.my_instance.data[0], 5)
def test_another_function(self):
# Another test using self.my_instance
self.my_instance.append_item(10)
self.assertEqual(len(self.my_instance.data), 1)
self.assertEqual(self.my_instance.data[0], 10)
Grouping Tests with Classes
setUp and tearDown methods.
Test Suites
unittest provides its own suite mechanism, tools like pytest often provide more flexible and powerful ways to manage test execution.
Using a Test Runner (pytest)
pytest is a popular and powerful test runner for Python. It offers features like auto-discovery of tests, detailed error reporting, and a rich plugin ecosystem. To use pytest, simply install it (pip install pytest) and run the pytest command in your project directory. pytest automatically discovers test files and functions named test_*.py and test_*, respectively.
Concepts Behind the Snippet
Real-Life Use Case Section
tests/
api/
test_user_endpoints.py
test_product_endpoints.py
models/
test_user_model.py
test_product_model.py
utils/
test_email_utils.py
This organization allows you to run tests specific to the API, the data models, or utility functions.
Best Practices
Interview Tip
When to Use Them
Alternatives
Pros
Cons
FAQ
-
What if my project has a flat structure with no modules?
Even in a flat structure, it's still beneficial to create atestsdirectory. Inside thetestsdirectory, you can create test files named after the corresponding source files. For example, if you have a file namedmain.py, you would create atest_main.pyfile in thetestsdirectory. -
How do I handle testing private functions or methods?
Testing private functions or methods directly is generally discouraged, as it can lead to brittle tests that are tightly coupled to the implementation details. Instead, focus on testing the public interface of your classes and modules. If you find yourself needing to test a private function extensively, it might indicate that the function's logic should be moved to a separate, testable module. -
Is it okay to have multiple test classes in a single test file?
Yes, it is acceptable to have multiple test classes in a single test file, especially if the classes are closely related or testing different aspects of the same unit of code. However, keep the file organized and ensure that each class has a clear purpose.