Python Programming · Foundations
Basic Testing
On this page 9 sections
In 30 seconds
A test is a small, repeatable check of an expected program behavior. In Python's standard unittest framework, a test case An individual check of a specified behavior under stated conditions. Full entry → usually places an assertion A test statement that checks whether an observed condition or value matches an expectation. Full entry → in a method on a unittest.TestCase subclass. Give the code controlled inputs, state the expected result The outcome a test says should occur for its stated case. Full entry →, and let the assertion report whether actual and expected agree. Useful basic tests are specific and deterministic Producing the same outcome when given the same controlled conditions. Full entry →: the same controlled setup should lead to the same expected outcome.
Why this matters
Tests make a program's expected behavior visible and checkable. In a course, they turn a vague claim such as ‘my function works’ into cases another person can run. In practice, a small test can catch a changed result close to the code that produced it. Tests also improve design: a focused function with a clear input and expected output is easier to check than a large script whose behavior depends on many hidden conditions.
The college version
A test makes one expectation executable
Software testing compares observed program behavior with an expectation. A basic test is not proof that every possible use of a program is correct; it is evidence about one stated case. For a function such as add, a useful expectation can be precise: with inputs 2 and 3, the result should be 5. The test runs the code, obtains the actual result The outcome produced when the code under test runs. Full entry →, and uses an assertion to compare it with the expected result. If they differ, the test fails and gives the reader a location and a description of the violated expectation. If they agree, that particular check passes.
Python includes the unittest unit-testing framework in its standard library. A common form is a class that inherits from unittest.TestCase, with test methods whose names begin with test. In those methods, assertion helpers express different kinds of expectations. assertEqual(actual, expected) checks equality; assertTrue(condition) checks that a condition is true; and assertRaises checks that a specified operation raises an expected exception. Choose the assertion that states the behavior clearly rather than writing an opaque check. This lesson emphasizes value comparisons with assertEqual; exception design and debugging workflow need their own focused lessons.
A test case is the individual unit of testing: it checks a particular response for a particular set of conditions. A suite is a collection of test cases, so do not use the two names as if they mean the same thing. TestCase is also the Python class that supplies assertion methods to a test class. The overlapping vocabulary is manageable when context is explicit: a test class inherits from unittest.TestCase, and each test method states an individual case.
Arrange, act, assert keeps the check legible
A compact way to organize a test is arrange, act, assert. Arrange establishes only the data or objects needed for the case. Act performs the operation being checked. Assert compares the observed result with the expectation. These labels describe roles, not required Python keywords. They help readers locate the setup, the behavior under test, and the judgment. In a very small test, a separate variable for every role may be unnecessary, but the logical order should still be visible.
For example, to test add(2, 3), arrange the two known integers, act by calling add, and assert that the returned value is 5. A test that silently performs several unrelated actions has a weak signal: when it fails, the reader must determine which behavior was meant to be checked. Prefer a focused test name such as test_adds_two_positive_integers. The name records the case, not a general claim that addition works in all circumstances. A second test can state another behavior, such as the identity effect of adding zero.
A fixture Preparation needed to run one or more tests. Full entry → is preparation needed for one or more tests. For the small arithmetic example, local values inside a test method are enough. When multiple tests need the same setup, unittest provides setUp, which runs before each test method. Setup is useful only when it makes tests clearer; shared, mutable setup can conceal what each test needs. This lesson does not turn fixtures into a lifecycle tutorial. The practical principle is simpler: establish the minimum controlled state needed to make the expected outcome understandable.
Determinism and the limit of a passing test
A deterministic test produces the same result when it starts with the same controlled conditions. A test of add(2, 3) is deterministic because the calculation has no dependency on a clock, network service, file already on a machine, or unseeded random value. Determinism matters because a failure should point to a changed behavior rather than an accidental difference in the environment. If code needs time, random numbers, a database, or a web service, a later testing design can supply a controlled substitute or fixed input. Do not treat a test that sometimes passes and sometimes fails as trustworthy evidence.
A passing test has a narrow meaning: the program matched that test's expectation for that case. It does not establish that every input, boundary, failure mode, or interaction is correct. The expectation itself can also be wrong, so tests deserve review just as production code does. Add cases because they distinguish meaningful behaviors—for example, ordinary inputs, a boundary condition, or an input that should be rejected—not merely to increase a count. Basic tests are most valuable when their names, setup, expected results, and assertions let another reader see exactly what evidence they provide.
Keep testing separate from debugging. A failed test reports a mismatch; debugging is the later investigation of why that mismatch occurred. Keep it separate from a deep pytest discussion as well: pytest is a third-party framework, whereas this lesson uses the standard-library unittest vocabulary. The transferable habit is to state a small expected behavior, run it under controlled conditions, and read the result as evidence with clear limits.

Eli explains
The same idea, in plain words
Explain it like I’m 10
A test is like checking one answer on a worksheet with an answer key. First, choose a small question with a known answer. Then let the program answer it. An assertion is the checker that compares the program's answer with the answer key. A pass means the answers matched for that one question; it does not mean the program answered every possible question correctly. Keeping the question controlled matters. If someone changes the question while you check it, the result is not a fair repeatable test. Each carefully chosen question adds a small piece of evidence, not a guarantee.
Picture it like this
Arrange-act-assert is like setting up a balance scale: place known items on the scale, let the scale settle, then check whether it shows the expected balance.
Where the picture stops working
A program test can inspect values, conditions, and expected errors, not only a physical balance. The analogy explains the sequence and comparison, not every kind of test.
Worked example
This executable example checks two stated behaviors of a small function. Run it with Python 3:
import unittest
def add(left, right):
return left + right
class AddTests(unittest.TestCase):
def test_adds_positive_integers(self):
actual = add(2, 3) # act
self.assertEqual(actual, 5) # assert
def test_zero_is_an_identity(self):
self.assertEqual(add(0, 7), 7)
if __name__ == "__main__":
unittest.main()The first test arranges the known inputs 2 and 3, acts by calling add, and asserts the expected result 5. The second case checks a different stated behavior. Both are deterministic: the same integer inputs lead to the same arithmetic results. If add were changed to subtract, the first assertion would fail. Passing both tests would support only these two cases, not every possible input to add.
Key takeaway
Write a basic test as a specific, controlled expectation: arrange the needed state, act on the code, and assert the expected result. A pass is useful evidence for that case, while deterministic setup makes the evidence repeatable.
Quick check
3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.
In Python's
Which assertion best states that add(2, 3) should produce 5?
Which sequence best describes arrange-act-assert for testing add(2, 3)?
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related
You’ll learn to
- Define a test case, assertion, expected result, and actual result.
- Explain how
unittest.TestCaseand an assertion express a basic Python test. - Apply arrange-act-assert to a deterministic function.
- Distinguish a deterministic test from a test that depends on uncontrolled time, randomness, or external state.
- Evaluate whether a test checks one stated behavior.
Common mistakes
Treating one passing test as proof that all behavior is correct.
State the precise case the test covers and add distinct cases for other meaningful behaviors.
Writing a test whose expected result depends on the current clock, a network response, or an unseeded random value.
Control those dependencies or use fixed inputs so repeated runs have a stable expectation.
Combining several unrelated behaviors in one test method.
Give each focused behavior its own test so a failure has a clear meaning.
Using
assertTruefor every comparison.Use a specific assertion such as
assertEqualwhen it communicates the expected and actual values directly.
Easily confused
test case vs. test suite
A test case is one individual check; a test suite is a collection of test cases or suites.
passing test vs. proof of overall correctness
A pass supports the stated case only; it does not cover untested inputs or expectations.
deterministic test vs. environment-dependent test
A deterministic test has a stable outcome for controlled conditions; an environment-dependent test can change with uncontrolled state.
Key vocabulary
- test case
- An individual check of a specified behavior under stated conditions.
- assertion
- A test statement that checks whether an observed condition or value matches an expectation.
- expected result
- The outcome a test says should occur for its stated case.
- actual result
- The outcome produced when the code under test runs.
- TestCase
- The
unittestclass that provides assertion methods for user-defined test classes. - fixture
- Preparation needed to run one or more tests.
- deterministic
- Producing the same outcome when given the same controlled conditions.
Sources & references
- unittest — Unit testing framework — Python Software Foundation
- unittest — Unit testing framework: Basic example — Python Software Foundation
EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.
Researched 2026-08-19
Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.

