Testing
Rationale
Testing ensures code reliability, prevents regressions, and improves maintainability. Automated tests help catch bugs early and support refactoring.
Unit Testing
Write unit tests for individual functions and modules. Use frameworks like Jest or Mocha for automated testing.
// Good: Jest unit test
import { add } from './math';
test('adds two numbers', () => {
expect(add(2, 2)).toBe(4);
});
// Bad: No assertions or unclear test
it('should work', () => {
add(2, 2);
});
- Mock dependencies to isolate the unit under test.
- Test edge cases and invalid input.
Integration Testing
Test interactions between multiple modules or components. Validate workflows and data flow.
// Good: Integration test with supertest (Node.js)
const request = require('supertest');
const app = require('../app');
describe('User API', () => {
it('registers a user', async () => {
const res = await request(app)
.post('/register')
.send({ name: 'Jane', email: 'jane@example.com', password: 'pass' });
expect(res.statusCode).toBe(201);
});
});
- Assert responses, redirects, and database changes.
- Test authentication, authorization, and validation.
End-to-End (E2E) Testing
Test user flows and scenarios using tools like Cypress or Playwright.
// Good: Cypress E2E test
it('logs in and views dashboard', () => {
cy.visit('/login');
cy.get('input[name=email]').type('user@example.com');
cy.get('input[name=password]').type('password');
cy.get('button[type=submit]').click();
cy.url().should('include', '/dashboard');
});
Mocking
Use mocking libraries to isolate tests and simulate external dependencies.
// Good: Jest mock
jest.mock('./api');
import { fetchUser } from './api';
fetchUser.mockResolvedValue({ name: 'John' });
- Mock services, modules, and events.
- Use dependency injection for easier mocking.
Test Data Setup
- Use factories or fixtures for test data.
- Reset state between tests to avoid side effects.
CI/CD Integration
- Run tests automatically in CI/CD pipelines (GitHub Actions, GitLab CI, etc.).
- Fail builds on test failures to prevent regressions.
Best Practices
- Write tests for all new features and bug fixes.
- Use descriptive test names and group related tests.
- Run tests automatically in CI/CD pipelines.
- Aim for high code coverage, but prioritize meaningful tests.
- Document test structure and conventions for new team members.
- Organize tests in
__tests__/,tests/, or alongside modules. - Use descriptive test names and group related tests in files.
- Document test structure and conventions for new team members.
- Prioritize meaningful tests over coverage percentage.