Typorithm · medium

Tests that reject a plausible wrong filter

pythonscriptingdata-boundariesindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Tests that reject a plausible wrong filter

0%

Concept and contract

Use independent exact expectations and prove a test fails when the implementation is deliberately wrong.

A useful test must distinguish the intended implementation from plausible wrong behavior. The worked unittest suite checks exact active-country membership and an empty match. Its fixture contains an active foreign row and an archived local row so an or-for-and defect becomes observable.

The lab first runs the accepted tests normally, then replaces active_ids with a controlled wrong-or implementation and runs them again. The accepted suite must fail that second run. This establishes a concrete oracle property instead of treating any green test execution as sufficient evidence.

Mechanism and worked example

unittest discovers methods beginning with test on the TestCase class.

unittest discovers methods beginning with test on the TestCase class. assertEqual compares the actual result with an independently written expected list. Each test receives a fresh fixture so one test's changes cannot quietly contaminate another test or make its outcome depend on execution order.

The source function and the tests remain separate even though they share one small teaching file. A main guard permits direct unittest execution without running the suite when the file is imported by the companion verifier. The earlier import-lifetime lesson therefore still applies.

Complete worked example

python

import unittest
from copy import deepcopy

def active_ids(rows, country):
    return sorted(row["id"] for row in rows
                  if row["active"] and row["country"] == country)

def fixture():
    return [{"id": "r1", "country": "UA", "active": True},
            {"id": "r2", "country": "US", "active": True},
            {"id": "r3", "country": "UA", "active": False}]

class FilterTests(unittest.TestCase):
    def test_combined_filters(self):
        self.assertEqual(active_ids(fixture(), "UA"), ["r1"])

    def test_no_match(self):
        self.assertEqual(active_ids(fixture(), "IL"), [])

if __name__ == "__main__":
    unittest.main()
Reasoning
Exact membership and an empty result reject the controlled wrong-or implementation.

Counterexamples and common mistakes

The counterexample asserts only that the positive result is nonempty.

The counterexample asserts only that the positive result is nonempty. The wrong-or implementation also returns a nonempty result, so the test misses the defect. Matching output length alone would also miss some wrong-membership cases; exact identities make the intended population reviewable.

Do not derive the expected output by copying the same filter expression into the test. That can duplicate the implementation mistake instead of challenging it. Choose a small fixture and calculate its expected members by hand before deciding how the implementation should be written.

Counterexample: a plausible but incorrect implementation

python

import unittest
from copy import deepcopy

def active_ids(rows, country):
    return sorted(row["id"] for row in rows
                  if row["active"] and row["country"] == country)

def fixture():
    return [{"id": "r1", "country": "UA", "active": True},
            {"id": "r2", "country": "US", "active": True},
            {"id": "r3", "country": "UA", "active": False}]

class FilterTests(unittest.TestCase):
    def test_some_result(self):
        self.assertTrue(active_ids(fixture(), "UA"))

if __name__ == "__main__":
    unittest.main()
Reasoning
A nonempty-result assertion also passes the wrong implementation.

Independent practice: small Python task

Add a test that proves the function preserves caller-owned input, while retaining the existing membership and empty-result checks.

Add a test that proves the function preserves caller-owned input, while retaining the existing membership and empty-result checks. Create a deep snapshot of a fresh fixture, call active_ids, then compare the source with that snapshot. The task adds one focused property rather than a new test framework.

The lab additionally substitutes a function that reverses its input before returning the otherwise correct sorted identities. Your completed practice suite must reject that mutation. This ensures an empty placeholder test cannot satisfy the new requirement merely by existing in the file.

Step 1: Create a fresh fixture and independent deep snapshot. Step 2: Compare the original rows after calling active_ids.

Practice starter: solve before reading the solution

python

import unittest
from copy import deepcopy

def active_ids(rows, country):
    return sorted(row["id"] for row in rows
                  if row["active"] and row["country"] == country)

def fixture():
    return [{"id": "r1", "country": "UA", "active": True},
            {"id": "r2", "country": "US", "active": True},
            {"id": "r3", "country": "UA", "active": False}]

class FilterTests(unittest.TestCase):
    def test_combined_filters(self):
        self.assertEqual(active_ids(fixture(), "UA"), ["r1"])

    def test_no_match(self):
        self.assertEqual(active_ids(fixture(), "IL"), [])

    def test_input_unchanged(self):
        # Snapshot fresh input, call the function and compare the source.
        raise NotImplementedError

if __name__ == "__main__":
    unittest.main()
Reasoning
Add a real source-preservation assertion using a fresh deep snapshot.
  • Hint 1: Do not compare the returned result with the snapshot of source rows.
  • Hint 2: The source itself must remain equal to its pre-call snapshot.

Solution, tests and trade-offs

The solution adds the input-preservation assertion and still passes the correct implementation.

The solution adds the input-preservation assertion and still passes the correct implementation. It detects both the wrong eligibility predicate and the deliberately mutating implementation. The original two tests remain relevant because a mutation check alone would not establish which identities should be selected.

These controlled substitutions demonstrate specific defects, not complete correctness for all possible inputs. The contract still assumes validated role records. Broader boundary testing and independent review remain necessary when this function is placed inside a real data-import or account system.

Practice solution and acceptance checks

python

import unittest
from copy import deepcopy

def active_ids(rows, country):
    return sorted(row["id"] for row in rows
                  if row["active"] and row["country"] == country)

def fixture():
    return [{"id": "r1", "country": "UA", "active": True},
            {"id": "r2", "country": "US", "active": True},
            {"id": "r3", "country": "UA", "active": False}]

class FilterTests(unittest.TestCase):
    def test_combined_filters(self):
        self.assertEqual(active_ids(fixture(), "UA"), ["r1"])

    def test_no_match(self):
        self.assertEqual(active_ids(fixture(), "IL"), [])

    def test_input_unchanged(self):
        rows = fixture()
        before = deepcopy(rows)
        active_ids(rows, "UA")
        self.assertEqual(rows, before)

if __name__ == "__main__":
    unittest.main()
Reasoning
The completed suite rejects an input-reversing implementation as well as wrong eligibility.

Interview reasoning and next step

In an interview, explain fixture choice, independence of expected values and the defect each assertion can reject.

In an interview, explain fixture choice, independence of expected values and the defect each assertion can reject. Show a test that passes for the intended behavior and fails for a meaningful controlled alternative. This is clearer evidence than counting test methods or maximizing coverage without an oracle.

The capstone combines validation, identity conflict handling and a deterministic report. Use the same small-case discipline: include invalid representations, duplicate observations, conflicting identities and an empty eligible result before trusting its summary.

Optional stretch — after the core task works: Write a new controlled defect and explain which existing test rejects it or which additional assertion is needed.

Computer practice: https://applydjinn.com/typorithm/python-lab-20261105.zip. Run verify.py with your selected Python interpreter, then complete an exercise and check it with --practice followed by the lesson id. The lab uses only the standard library and disposable local fixtures; it never connects to the production database or company feeds.

Use independent exact expectations and prove a test fails when the implementation is deliberately wrong.