🎓 A1Learner
🔍

Python Organising Tests

Test organization is the way a test class shares setup and names its tests. setUp builds fresh state before each test.

Share setup with setUp

Every test in this class starts from the same fresh account.

class TestBankAccount(unittest.TestCase):
    def setUp(self):
        self.account = BankAccount("Ana", 100)

Clean up with tearDown

tearDown runs after each test, even when the test fails.

class TestReport(unittest.TestCase):
    def setUp(self):
        self.file = open("report.txt", "w")

    def tearDown(self):
        self.file.close()

Names that read as sentences

A reader can scan these names and know the rules of the account.

def test_deposit_adds_money(self):
    ...

def test_withdraw_removes_money(self):
    ...

def test_new_account_starts_at_zero(self):
    ...

Skip a test for now

A skipped test still counts as found. It just does not run.

import io
import unittest

class TestDemo(unittest.TestCase):
    def test_ready(self):
        self.assertTrue(True)

    @unittest.skip("waiting for the new parser")
    def test_future(self):
        self.assertTrue(False)

suite = unittest.TestLoader().loadTestsFromTestCase(TestDemo)
stream = io.StringIO()
result = unittest.TextTestRunner(stream=stream).run(suite)
print("Tests run:", result.testsRun)
print("Skipped:", len(result.skipped))

Example

import unittest

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        self.balance -= amount

class TestBankAccount(unittest.TestCase):
    def setUp(self):
        self.account = BankAccount("Ana", 100)

    def test_deposit_adds_money(self):
        self.account.deposit(50)
        self.assertEqual(self.account.balance, 150)

    def test_withdraw_removes_money(self):
        self.account.withdraw(40)
        self.assertEqual(self.account.balance, 60)

    def test_new_account_starts_fresh(self):
        self.assertEqual(self.account.balance, 100)

if __name__ == "__main__":
    unittest.main()

Key points

  • Fixture: the ready-made state a test needs before it runs.
  • Use setUp to build fresh state before each test.
  • Use tearDown to clean up after each test.
  • Write one behaviour per test, so one failure names one problem.
  • Name a test like a sentence, such as test_deposit_adds_money.
  • Discovery: unittest finds files named test_*.py and runs their tests.
  • Use @unittest.skip to leave a test out for now, with a reason.
  • setUp runs before every single test, not once for the class.
  • Test organization means a class shares its setup and each test carries a clear name.

In this example, the whole program lives in one file, test_bank.py. Run it with python3 -m unittest test_bank. The setUp method builds a fresh account with 100 before each test. The deposit test cannot leak money into the withdraw test. The third test proves the start is fresh, because the balance is still 100. The Ran line also reports a time in seconds. That time changes on every run, so it is not shown here. OK means all three tests passed.

Note

Each test gets a truly fresh start.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Python Playground

Exercise

Why does setUp run before every test, not just once?