Unit testing is a way to verify that individual parts of your code work as expected. When you write tests for a Python class, you check that its methods return correct values, handle edge cases, and fail gracefully when given bad input. This guide walks you through writing tests using the built-in unittest framework, which requires no extra installation. You’ll learn how to structure tests, what to test, and how to avoid common pitfalls.
What You’ll Need
- Python 3 installed on your machine (any recent version works).
- A text editor or IDE (VS Code, PyCharm, or even Notepad).
- The class you want to test, saved in a .py file (e.g.,
calculator.py). - A basic understanding of Python classes and methods.
Step-by-Step
- Create a separate test file. Name it
test_<your_module>.py(e.g.,test_calculator.py). This keeps tests isolated from your source code and makes it easy to run them with test runners. - Import the class you want to test. At the top of the test file, import the class from its module. If your class is in
calculator.py, writefrom calculator import Calculator. Make sure the test file is in the same directory or adjust the import path. - Import the unittest module. Add
import unittestat the top. This gives you access toTestCaseand assertion methods. - Create a test class that inherits from
unittest.TestCase. For example:class TestCalculator(unittest.TestCase):. This class will group all tests for theCalculatorclass. - Write test methods inside the test class. Each method should start with the word
test_(e.g.,test_add). This naming convention lets unittest automatically discover and run them. - Set up objects in
setUpif needed. If your class requires initialization, create an instance in asetUp(self)method so each test starts with a fresh object. For example:def setUp(self): self.calc = Calculator(). This avoids repeating code and prevents state from leaking between tests. - Use assertion methods to check expected behavior. Common ones:
assertEqual(a, b)checks equality,assertTrue(x)checks if x is True,assertFalse(x)checks if x is False,assertRaises(SomeException, callable, *args)checks that an exception is raised. - Test each method with normal inputs first. For example, if you have an
add(a, b)method, testself.assertEqual(self.calc.add(2, 3), 5). - Test edge cases and invalid inputs. Try zero, negative numbers, very large numbers, or wrong types. Use
assertRaisesto verify that the method raises aValueErrororTypeErrorwhen appropriate. - Test methods that modify state. If your class has a counter or a list that changes, call the method and then assert the new state. For example,
self.calc.increment()thenassertEqual(self.calc.count, 1). - Run your tests. In the terminal, navigate to the directory containing your test file and run
python -m unittest test_calculator.py. You can also runpython -m unittest discoverto find all test files in the current directory. - Read the output. If all tests pass, you’ll see a dot for each test and an OK message. If any fail, you’ll see an F and a detailed traceback showing which assertion failed and why.
Common Mistakes
- Not starting test method names with
test_– unittest will silently skip them, and you’ll get a false sense of security. - Testing multiple things in one test method – if one assertion fails, you won’t know if the others would have passed. Keep each test focused on one behavior.
- Forgetting to import the class or module – this causes a ModuleNotFoundError. Double-check your import paths.
- Using
assertinstead ofself.assert*methods – plainassertworks, but unittest’s methods give better failure messages and integrate with the runner. - Sharing mutable state between tests – if you create an object in
setUpand modify it, the next test may see the modified version. UsesetUpto create fresh instances each time. - Not testing invalid inputs – your class may crash on bad data; tests should catch that.
Tips
- Write tests before or right after writing the class – test-driven development (TDD) helps you design cleaner interfaces.
- Use descriptive test method names like
test_add_negative_numbersso failures are easy to understand. - Keep tests independent – each test should not depend on the order of execution.
- Use
setUpfor repetitive initialization, but avoid doing heavy work there – it runs before every test, so keep it fast. - Run tests frequently – after every change to your class, run the test suite to catch regressions early.
- Use
assertAlmostEqualfor floating-point comparisons – floating-point arithmetic can have tiny rounding errors, soassertEqual(0.1 + 0.2, 0.3)will fail. UseassertAlmostEqual(0.1 + 0.2, 0.3, places=7).
Troubleshooting
- No tests are run (0 tests) – Check that your test file is named starting with
test_or ending with_test.py. Also ensure your test methods start withtest_. - ImportError: No module named ‘your_module’ – Make sure the test file is in the same directory as the module, or add the parent directory to
sys.path. You can also runpython -m unittestfrom the root of your project. - Tests pass but you know there’s a bug – You might be testing the wrong behavior. Review your assertions to ensure they match what the method should actually do. Also check for side effects that aren’t being tested.
- AssertionError with floating-point numbers – Use
assertAlmostEqualinstead ofassertEqualfor non-integer results. - Tests fail because of side effects from previous tests – Ensure each test creates its own instance in
setUpor at the start of the test. Avoid using class-level mutable attributes. - Running from a different directory causes ‘no module named’ – Use
python -m unittest discover -s .from the project root, or setPYTHONPATH.
Frequently Asked Questions
Do I need to install anything to use unittest?
No, unittest is part of the Python standard library. Just import unittest and you’re ready.
Can I use pytest instead of unittest?
Yes, pytest is a popular third-party framework that often requires less boilerplate. However, unittest is built-in and works fine for most projects. You can also run unittest tests with pytest by installing pytest.
How do I test a class that requires external resources like a database?
You can use mocking to replace the external dependency with a fake. The unittest.mock module provides patch and MagicMock for this purpose.
What is the difference between setUp and setUpClass?
setUp runs before each test method, giving you a fresh state. setUpClass runs once before all tests in the class, which is useful for expensive setup that can be shared, but be careful with mutable state.
Should I test private methods (those starting with underscore)?
Generally, no. Test the public interface. Private methods are implementation details and may change. If you feel the need to test them, consider refactoring them into separate classes or functions.
How many tests should I write?
Aim for at least one test per public method, plus tests for edge cases and error handling. Quality matters more than quantity; a few well-targeted tests are better than dozens of trivial ones.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It