December 20, 2024 β’ 15 min read
Quality isn't just about writing testsβit's about building a culture and infrastructure that prevents bugs from reaching production. After implementing comprehensive quality engineering practices across multiple production systems, I've learned that the best testing strategies combine automated testing, static analysis, and continuous integration into a seamless development workflow.
The testing pyramid ensures maximum coverage with optimal execution speed and maintainability.
Effective unit tests should be fast, isolated, and provide clear feedback. Here's how we structure unit tests for complex business logic:
// PaymentProcessor.test.js - Comprehensive unit testing example import PaymentProcessor from '../PaymentProcessor'; import { mockPaymentGateway, mockAuditLogger } from '../__mocks__'; describe('PaymentProcessor', () => { let paymentProcessor; let mockGateway; let mockLogger; beforeEach(() => { mockGateway = mockPaymentGateway(); mockLogger = mockAuditLogger(); paymentProcessor = new PaymentProcessor(mockGateway, mockLogger); }); describe('processPayment', () => { it('should successfully process a valid payment', async () => { // Arrange const paymentRequest = { amount: 99.99, currency: 'AUD', cardToken: 'tok_1234567890', customerId: 'cus_test123' }; mockGateway.charge.mockResolvedValue({ id: 'charge_test123', status: 'succeeded', amount: 9999 }); // Act const result = await paymentProcessor.processPayment(paymentRequest); // Assert expect(result.success).toBe(true); expect(result.chargeId).toBe('charge_test123'); expect(mockLogger.logPaymentSuccess).toHaveBeenCalled(); }); it('should handle payment failures gracefully', async () => { mockGateway.charge.mockRejectedValue({ type: 'card_error', code: 'card_declined' }); const result = await paymentProcessor.processPayment({ amount: 50.00, currency: 'AUD' }); expect(result.success).toBe(false); expect(result.error.type).toBe('card_error'); }); }); });
End-to-end tests validate complete user journeys. Here's how we implement robust E2E testing:
// cypress/e2e/checkout-flow.cy.js describe('E-commerce Checkout Flow', () => { beforeEach(() => { cy.task('db:seed'); cy.intercept('POST', '/api/payments/process', { fixture: 'payment-success.json' }).as('processPayment'); }); it('completes full purchase journey', () => { cy.visit('/products/wireless-headphones'); cy.get('[data-testid="add-to-cart-btn"]').click(); cy.get('[data-testid="checkout-btn"]').click(); // Fill shipping information cy.get('input[name="email"]').type('test@example.com'); cy.get('input[name="address"]').type('123 Test Street'); // Fill payment information cy.get('input[name="cardNumber"]').type('4242424242424242'); cy.get('input[name="expiryDate"]').type('12/25'); cy.get('[data-testid="complete-purchase-btn"]').click(); cy.wait('@processPayment'); cy.url().should('include', '/order-confirmation'); cy.get('[data-testid="order-confirmation"]') .should('contain', 'Order Confirmed'); }); });
Automated quality checks prevent poor code from entering the repository:
# .husky/pre-commit #!/usr/bin/env sh echo "π Running pre-commit checks..." # Lint staged files npx lint-staged # Type checking npx tsc --noEmit # Security audit npm audit --audit-level moderate echo "β Pre-commit checks completed!" # package.json scripts { "scripts": { "test:unit": "jest --testPathPattern=__tests__/unit", "test:integration": "jest --testPathPattern=__tests__/integration", "test:e2e": "cypress run", "lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix", "prepare": "husky install" } } # lint-staged.config.js module.exports = { '*.{js,jsx,ts,tsx}': [ 'eslint --fix', 'prettier --write', 'jest --findRelatedTests --passWithNoTests' ] };
# sonar-project.properties sonar.projectKey=quality-engineering-example sonar.organization=handy-hasan sonar.sources=src sonar.tests=src sonar.test.inclusions=**/*.test.js,**/*.spec.js sonar.javascript.lcov.reportPaths=coverage/lcov.info # GitHub Actions Quality Pipeline name: Quality Analysis on: [push, pull_request] jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: npm ci - name: Run tests with coverage run: npm run test:coverage - name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Quality engineering transformed how we ship software at The Good Guys. Our comprehensive testing strategy reduced production bugs by 85% and increased developer confidence. The upfront investment in quality infrastructure pays dividends in faster delivery and fewer production issues.