Writing your first Python unit test takes less than five minutes. You do not need to install anything or set up a special project structure. If Python is installed on your computer, you already have the unittest module built in.
A unit test checks one small piece of behavior in isolation. If you have a function that validates a password, the unit test calls that function with a known input and checks that the returned value matches your expectation. It does not care about databases, network connections, or other parts of your application.
This article assumes you have read how to test Python code and are comfortable with Python functions. You will create a small function, write a test class, run the tests, read the output, and intentionally break something to see what a failure looks like.
Create a function to test
Start with a small, realistic function. This example checks whether a password meets a minimum length requirement, a common validation task that is simple enough to test thoroughly but real enough to matter.
def is_strong_password(password):
if len(password) >= 8:
return True
return FalseSave this in a file named password_checker.py. The function is straightforward: a password is strong if it has eight or more characters, and weak otherwise.
Write your first test case
Create a new file named test_password_checker.py in the same directory. You will import both unittest and the function you want to test, then create a class that inherits from unittest.TestCase. The class groups related tests together so the framework can discover and run them as a batch.
import unittest
from password_checker import is_strong_password
class TestPasswordChecker(unittest.TestCase):
def test_short_password(self):
result = is_strong_password("abc")
self.assertFalse(result)
def test_long_password(self):
result = is_strong_password("mysupersecretpassword")
self.assertTrue(result)
if __name__ == "__main__":
unittest.main()Each method whose name starts with test_ becomes a separate test. The method names describe the scenario, which matters because they appear in the output when a test fails. Use assertTrue when you expect True, and assertFalse when you expect False. The block at the bottom lets you run the file as a script; unittest.main() discovers all test methods and runs them.
Run the tests
Open your terminal, navigate to the directory containing both files, and run the test file:
python test_password_checker.pyunittest prints a short summary to the terminal rather than the details of every test, so a successful run is easy to spot at a glance. When both tests pass, the output looks like this:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKEach dot represents one passing test, and OK means every assertion was satisfied. This confirmation tells you that your function behaves correctly for the inputs you tested.
You can also run the tests with the module syntax, which gives you access to extra options. The verbose flag is useful when you have many tests and need to see precisely which ones ran:
python -m unittest test_password_checker.pyAdd the -v flag for verbose output, which prints each test name on its own line instead of dots.
See what a test failure looks like
A passing test is reassuring, but understanding a failing test is equally important. Add a deliberate bug by changing the threshold from eight to ten characters:
def is_strong_password(password):
if len(password) >= 10:
return True
return FalseRun the tests again. The test for an eight-character password now fails because the function requires ten characters while the test still expects eight to count as strong. Here is what the failure output shows:
.F
======================================================================
FAIL: test_exactly_eight_characters (__main__.TestPasswordChecker.test_exactly_eight_characters)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_password_checker.py", line 12, in test_exactly_eight_characters
self.assertTrue(result)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)Read the output from bottom to top. The summary confirms one failure out of two. The AssertionError tells you the actual value, and the traceback points to the exact line.
This feedback loop is the core of testing. Change your code, run the tests, and the framework tells you which expectation no longer holds.
Fix the threshold back to eight, run again, and you are back to OK.
Add tests for edge cases
Two tests are a good start, but your test suite should also cover boundary values where bugs often hide. For a password length check, add tests for an empty string, a password of exactly eight characters, and a None input.
def test_empty_password(self):
result = is_strong_password("")
self.assertFalse(result)
def test_exactly_eight_characters(self):
result = is_strong_password("abcdefgh")
self.assertTrue(result)
def test_password_is_none(self):
with self.assertRaises(TypeError):
is_strong_password(None)The first two tests check the boundary at exactly eight characters. The third test uses assertRaises, which expects the code inside the with block to raise a TypeError. If the function raises a TypeError when given None, the test passes because the code correctly refuses invalid input.
A good unit test is independent, fast, and readable. Independence means one test does not rely on the side effects of another test. Fast means each test runs in milliseconds so you can run the whole suite after every save. Readable means someone unfamiliar with the code can look at the test name and the assertion and understand what the function is supposed to do.
Avoid these common mistakes. Do not test Python built-in behavior like checking that len() works. Do not write a test that calls five unrelated functions and asserts ten things at once. Do not skip the assertion and just call the function without checking the result; a test without an assertion always passes, which gives false confidence.
The next article covers Python unittest explained in depth, including setUp and tearDown for sharing test data, the full set of assertion methods, and how to skip tests that are not ready to run.
Rune AI
Key Insights
- A unit test is a small, focused check on a single function or method, written with assertion methods like assertEqual.
- Create a test case by subclassing unittest.TestCase and writing methods that start with
test_. - Run the test file directly with
python test_file.pyor withpython -m unittest test_file. - A passing test shows a dot and an OK summary; a failing test shows an F followed by the expected and actual values.
- Write tests that cover the happy path, edge cases, and error conditions for each function.
Frequently Asked Questions
What is the difference between a unit test and an integration test?
Do I need a special file structure to run unittest?
What does a passing test output look like versus a failing one?
Conclusion
Your first unit test is a small milestone that opens a larger practice. Once you have written one test and watched it pass, you have the basic pattern you need for every test you will write from here forward. Add a test every time you write a function, and over time your project will carry its own safety net.
More in this topic
How to Test Python Code
Learn what testing means in Python, the core ideas behind automated tests, and the built-in and third-party tools that make testing practical.
The Factory Pattern in Python
Learn how to use the factory pattern in Python to encapsulate object creation, making your code more flexible and easier to extend.
Organize and Run Python Tests
Learn how to structure test directories, run tests with unittest and pytest, configure test discovery, and integrate tests into your workflow.