Python Programming · Foundations

Basic Testing

Want it in plain words first? Jump to Eli explains — the same idea, no jargon.
On this page 9 sections
  1. In 30 seconds
  2. Why this matters
  3. The college version
  4. Eli explains
  5. Worked example
  6. Key takeaway
  7. Quick check
  8. Study tools
  9. Sources & references

In 30 seconds

A test is a small, repeatable check of an expected program behavior. In Python's standard unittest framework, a usually places an in a method on a unittest.TestCase subclass. Give the code controlled inputs, state the , and let the assertion report whether actual and expected agree. Useful basic tests are specific and : 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 , 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 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, the EliExplains learning guide

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.

Question 1 of 3foundational

In Python's unittest framework, what is a test case?

Choose an answer, then check it.
Question 2 of 3intermediate

Which assertion best states that add(2, 3) should produce 5?

Choose an answer, then check it.
Question 3 of 3intermediate

Which sequence best describes arrange-act-assert for testing add(2, 3)?

Choose an answer, then check it.
Practice all 5

Keep learning

Ready to build on this? Continue to the next lesson.

Practice this lesson
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.TestCase and 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 assertTrue for every comparison.

    Use a specific assertion such as assertEqual when 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 unittest class 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

  1. unittest — Unit testing framework — Python Software Foundation
  2. 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.