Latest update Android YouTube

Unit Test | Testing in Python

Enterprise Python Testing with unittest

Industrial-strength testing patterns with Python's built-in framework

1. Test Cases (Industrial Strength Patterns)

Core Architecture

import unittest

class DatabaseTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Class-level setup (runs once)"""
        cls.engine = create_engine('sqlite:///:memory:')
        Base.metadata.create_all(cls.engine)
    
    def setUp(self):
        """Per-test setup (runs before each test)"""
        self.connection = self.engine.connect()
        self.transaction = self.connection.begin()
    
    def tearDown(self):
        """Per-test cleanup (runs after each test)"""
        self.transaction.rollback()
        self.connection.close()
    
    def test_record_creation(self):
        """Test method (must start with 'test_')"""
        record = self.connection.execute("INSERT INTO...")
        self.assertGreater(record.lastrowid, 0)

Advanced Patterns

# Dynamic test generation
def load_tests(loader, standard_tests, pattern):
    suite = unittest.TestSuite()
    # Add standard tests
    suite.addTests(standard_tests)
    # Add dynamic tests
    for scenario in load_scenarios():
        test_case = create_test_case(scenario)
        suite.addTest(test_case)
    return suite

# Test mixin pattern
class LoggingMixin:
    def assertLogsOutput(self, logger, level, message):
        with self.assertLogs(logger, level) as cm:
            # Test code that should log
            self.assertIn(message, cm.output[0])

Enterprise Example

class TransactionalAPITest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.app = create_test_app()
        cls.client = cls.app.test_client()
        cls.db = create_test_db()
    
    def setUp(self):
        self.db.begin_transaction()
    
    def tearDown(self):
        self.db.rollback_transaction()
    
    def test_api_endpoint(self):
        response = self.client.post('/api/data', json={'key': 'value'})
        self.assertEqual(response.status_code, 201)
        self.assertIn('Location', response.headers)

2. Assertions (Production Validation Toolkit)

Core Assertions

Method Equivalent To Use Case
assertEqual(a, b) a == b Value equality
assertTrue(x) bool(x) is True Boolean truth
assertRaises(Exc, func) with pytest.raises(Exc) Exception testing
assertIs(a, b) a is b Identity check

Advanced Validation

# Floating point comparison
self.assertAlmostEqual(0.1 + 0.2, 0.3, places=7)

# Collection assertions
self.assertCountEqual(['a', 'b', 'c'], ['b', 'c', 'a'])  # Unordered comparison

# Type validation
self.assertIsInstance(response.json(), dict)

# Regex matching
self.assertRegex(response.text, r'^Success: \d+ items')

Custom Assertions

def assertValidXML(self, xml_string):
    """Validate XML structure and schema"""
    try:
        etree.fromstring(xml_string)
        schema.assertValid(xml_string)
    except (etree.ParseError, etree.DocumentInvalid) as e:
        raise self.failureException(f"Invalid XML: {str(e)}")

# Register custom assertion
unittest.TestCase.assertValidXML = assertValidXML

# Usage in tests
def test_api_response(self):
    response = self.client.get('/data.xml')
    self.assertValidXML(response.data)

3. Test Suites (Enterprise Orchestration)

Basic Suite Construction

def suite():
    suite = unittest.TestSuite()
    # Add individual test methods
    suite.addTest(TestClass('test_method'))
    # Add multiple tests
    suite.addTests([
        TestClass2('test_feature_a'),
        TestClass2('test_feature_b')
    ])
    return suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

Advanced Composition

# Module-level test discovery
loader = unittest.TestLoader()
suite = loader.discover(start_dir='./tests', pattern='test_*.py')

# Hierarchical test suites
top_suite = unittest.TestSuite()
unit_suite = loader.loadTestsFromModule(test_unit)
integration_suite = loader.loadTestsFromModule(test_integration)
top_suite.addTests([unit_suite, integration_suite])

CI/CD Integration

python -m unittest discover -s ./tests -p 'test_*.py' Discover and run all tests
python -m unittest tests/test_module.py Run specific test module
python -m unittest --xml-report ./reports Generate JUnit XML reports
python -m unittest TestClass.test_method Run specific test method

4. Advanced unittest Features

Mocking Framework

from unittest.mock import patch, MagicMock

class APITest(unittest.TestCase):
    @patch('requests.get')
    def test_api_call(self, mock_get):
        # Configure mock
        mock_response = MagicMock()
        mock_response.json.return_value = {'key': 'value'}
        mock_get.return_value = mock_response
        
        # Test code that uses requests.get
        result = fetch_data()
        
        # Assertions
        mock_get.assert_called_once_with('https://api.example.com')
        self.assertEqual(result, {'key': 'value'})

Performance Testing

class PerformanceTests(unittest.TestCase):
    @unittest.skipUnless(os.getenv('PERF_TESTS'), 'Performance tests disabled')
    def test_response_time(self):
        """Verify API response time SLA"""
        start_time = time.perf_counter()
        make_api_call()
        duration = time.perf_counter() - start_time
        
        self.assertLess(duration, 0.5)  # 500ms SLA
        self.assertWarns(ResourceWarning, make_expensive_call)

Enterprise Tip: Combine unittest with the subTest context manager for data-driven tests without generating separate test cases.

5. Migration & Modernization

unittest → pytest Bridge

Feature unittest pytest
Fixtures setUp/tearDown @pytest.fixture
Assertions assert* methods Plain assert
Parametrization subTest @pytest.mark.parametrize
Test Discovery test_* methods More flexible patterns

When unittest Shines

  • Legacy systems: Django, stdlib modules
  • Strict xUnit needs: JUnit-compatible output
  • Team constraints: Developers familiar with JUnit-style
  • Corporate standards: Mandated testing frameworks

Migration Warning: While pytest can run unittest tests, some features like custom test loaders may need adaptation during migration.

6. Complete Enterprise Example

import unittest
import warnings
from decimal import Decimal
from unittest.mock import patch

class FinancialPortfolioTest(unittest.TestCase):
    """End-to-end test of portfolio management system"""
    
    @classmethod
    def setUpClass(cls):
        # Load test data once for all tests
        cls.test_data = load_large_dataset('portfolio_fixture.json')
        # Connect to test database
        cls.engine = create_engine(DB_URL)
        cls.metadata.create_all(cls.engine)
    
    @classmethod
    def tearDownClass(cls):
        # Clean up database
        cls.metadata.drop_all(cls.engine)
        cls.engine.dispose()
    
    def setUp(self):
        # Fresh transaction for each test
        self.connection = self.engine.connect()
        self.transaction = self.connection.begin()
        # Create fresh portfolio instance
        self.portfolio = Portfolio(self.connection)
        self.portfolio.initialize(self.test_data)
    
    def tearDown(self):
        # Rollback transaction
        self.transaction.rollback()
        self.connection.close()
    
    def test_portfolio_valuation(self):
        """Test valuation under market conditions"""
        with patch('finance.market_data.fetch') as mock_fetch:
            mock_fetch.return_value = {
                'AAPL': Decimal('175.50'),
                'MSFT': Decimal('250.75')
            }
            value = self.portfolio.current_value()
            self.assertIsInstance(value, Decimal)
            self.assertGreater(value, Decimal('10000'))
    
    @unittest.skipUnless(HAS_NETWORK, "Requires network access")
    def test_live_data_integration(self):
        """Integration test with live market data"""
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", ResourceWarning)
            value = self.portfolio.current_value()
            self.assertIsInstance(value, Decimal)
    
    def test_transaction_audit_log(self):
        """Verify audit trail for transactions"""
        with self.assertLogs('finance.audit', level='INFO') as cm:
            self.portfolio.execute_trade('AAPL', 10, 'BUY')
            self.assertIn('Trade executed', cm.output[0])
            self.assertIn('AAPL', cm.output[0])

def load_tests(loader, standard_tests, pattern):
    """Custom test loader for enterprise environment"""
    suite = unittest.TestSuite()
    # Add standard tests
    suite.addTests(standard_tests)
    # Add integration tests if enabled
    if os.getenv('RUN_INTEGRATION_TESTS'):
        suite.addTests(loader.discover('integration_tests'))
    return suite

if __name__ == '__main__':
    unittest.main(failfast=True)

Production Pattern: For large enterprise suites, combine unittest with concurrent.futures for parallel test execution across multiple modules.

Post a Comment

Feel free to ask your query...
Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.