Syntax Style: Class-based
Assertions: self.assertEqual(a, b)
Test preparation & cleanup: setUp / tearDown
Plugin Ecosystem: Small
Popularity in modern projects: Medium
Syntax Style: Function or class based
Assertions: assert a == b
Test preparation & cleanup: Fixtures (@pytest.fixture)
Plugin Ecosystem: Huge and powerful
Popularity in modern projects: Very High
The basic building block - individual test methods
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# Check that split fails when separator is not a string
with self.assertRaises(TypeError):
s.split(2)
Setup and teardown methods for test preparation and cleanup
class TestDatabaseOperations(unittest.TestCase):
def setUp(self):
"""Run before each test method"""
self.connection = create_test_connection()
self.cursor = self.connection.cursor()
self.cursor.execute("CREATE TABLE test (id INT, name VARCHAR(255))")
def tearDown(self):
"""Run after each test method"""
self.cursor.execute("DROP TABLE test")
self.connection.close()
@classmethod
def setUpClass(cls):
"""Run once before any tests in the class"""
cls.database_url = "sqlite:///test.db"
@classmethod
def tearDownClass(cls):
"""Run once after all tests in the class"""
import os
if os.path.exists("test.db"):
os.remove("test.db")
def test_insert(self):
self.cursor.execute("INSERT INTO test VALUES (1, 'John')")
# Test implementation...
def test_select(self):
# Test implementation...
pass
Collections of test cases
def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_split'))
suite.addTest(TestDatabaseOperations('test_insert'))
return suite
Alternative way to create suite
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(TestStringMethods)
class TestAssertions(unittest.TestCase):
def test_basic_assertions(self):
# Equality
self.assertEqual(1, 1)
self.assertNotEqual(1, 2)
# Boolean conditions
self.assertTrue(1 == 1)
self.assertFalse(1 == 2)
# Identity
self.assertIs(a, b) # a is b
self.assertIsNot(a, b) # a is not b
# None values
self.assertIsNone(x)
self.assertIsNotNone(x)
# Membership
self.assertIn(1, [1, 2, 3])
self.assertNotIn(4, [1, 2, 3])
# Comparisons
self.assertGreater(2, 1) # 2 > 1
self.assertGreaterEqual(2, 2) # 2 >= 2
self.assertLess(1, 2) # 1 < 2
self.assertLessEqual(1, 1) # 1 <= 1
# Approximate equality
self.assertAlmostEqual(0.1 + 0.2, 0.3, places=7)
self.assertNotAlmostEqual(0.1, 0.2, places=1)
# Regular expressions
self.assertRegex('hello world', r'hello')
self.assertNotRegex('hello world', r'goodbye')
# Types
self.assertIsInstance(5, int)
self.assertNotIsInstance('hello', int)
class TestExceptions(unittest.TestCase):
def test_exception_assertions(self):
# Check that specific exception is raised
with self.assertRaises(ValueError):
int('not a number')
# Check exception with specific message
with self.assertRaisesRegex(ValueError, 'invalid literal'):
int('XYZ')
# Check exception with context
with self.assertRaises(ValueError) as context:
int('NaN')
self.assertEqual(str(context.exception), "invalid literal for int()")
# Check no exception is raised
with self.assertRaises(AssertionError):
with self.assertRaises(ValueError):
int('123') # This won't raise ValueError
project/
├── src/
│ └── mymodule.py
├── tests/
│ ├── __init__.py
│ ├── test_basic.py
│ ├── test_advanced.py
│ └── integration/
│ └── test_integration.py
└── setup.py
# Run all tests in current directory and subdirectories
python -m unittest discover
# Run tests with more verbosity
python -m unittest discover -v
# Run specific test module
python -m unittest tests.test_basic
# Run specific test case
python -m unittest tests.test_basic.TestStringMethods
# Run specific test method
python -m unittest tests.test_basic.TestStringMethods.test_upper
# Run with pattern matching
python -m unittest discover -p "test_*.py"
# Run with custom start directory
python -m unittest discover -s tests/integration