General testing methodologies and best practices for web development
Project Status: ProyectoWeb is currently in the planning stage. This guide provides general testing best practices that can be applied when development begins.
// Good - tests behaviortest('calculates total price with tax', () => { const result = calculateTotal([10, 20], 0.1); expect(result).toBe(33);});// Avoid - tests implementation detailstest('calls reduce method', () => { const spy = jest.spyOn(Array.prototype, 'reduce'); calculateTotal([10, 20], 0.1); expect(spy).toHaveBeenCalled();});
2
Keep Tests Independent
Each test should run independently:
describe('User Service', () => { // Reset state before each test beforeEach(() => { jest.clearAllMocks(); database.clear(); }); test('creates user', () => { /* ... */ }); test('updates user', () => { /* ... */ });});
3
Use Descriptive Test Names
// Good - clear and descriptivetest('returns 400 when email is missing', () => { });test('allows admin to delete users', () => { });test('prevents user from accessing unauthorized content', () => { });// Avoid - vague or uncleartest('test1', () => { });test('it works', () => { });test('user test', () => { });
4
Follow AAA Pattern
Structure tests with Arrange, Act, Assert:
test('applies discount to order total', () => { // Arrange - set up test data const order = { items: [{ price: 100 }] }; const discount = 0.1; // Act - execute the code being tested const result = applyDiscount(order, discount); // Assert - verify the result expect(result.total).toBe(90);});
// Create a mock functionconst mockCallback = jest.fn();// Use it[1, 2, 3].forEach(mockCallback);// Verify it was calledexpect(mockCallback).toHaveBeenCalledTimes(3);expect(mockCallback).toHaveBeenCalledWith(1);
Mock Modules
// Mock entire modulejest.mock('./api', () => ({ getUser: jest.fn(), updateUser: jest.fn()}));// Import and use mocked moduleimport { getUser } from './api';test('uses API', async () => { getUser.mockResolvedValue({ id: '1', name: 'Test' }); const result = await someFunction(); expect(getUser).toHaveBeenCalled();});
Mock Return Values
const mock = jest.fn();// Return specific valuemock.mockReturnValue(42);expect(mock()).toBe(42);// Return different values on consecutive callsmock .mockReturnValueOnce(1) .mockReturnValueOnce(2) .mockReturnValue(3);expect(mock()).toBe(1);expect(mock()).toBe(2);expect(mock()).toBe(3);
Mock Implementations
const mock = jest.fn((x) => x * 2);expect(mock(5)).toBe(10);// Change implementationmock.mockImplementation((x) => x + 1);expect(mock(5)).toBe(6);
Write a test for the functionality you want to add:
test('formats phone number', () => { expect(formatPhoneNumber('1234567890')) .toBe('(123) 456-7890');});// This test will fail because formatPhoneNumber doesn't exist yet
2
Write Minimal Code
Write just enough code to make the test pass:
function formatPhoneNumber(number) { return `(${number.slice(0, 3)}) ${number.slice(3, 6)}-${number.slice(6)}`;}
3
Refactor
Improve the code while keeping tests green:
function formatPhoneNumber(number) { // Add validation if (number.length !== 10) { throw new Error('Invalid phone number length'); } return `(${number.slice(0, 3)}) ${number.slice(3, 6)}-${number.slice(6)}`;}
// Run only this testtest.only('focused test', () => { // This is the only test that will run});// Skip this testtest.skip('skipped test', () => { // This test will be skipped});
test('slow operation', async () => { // Increase timeout for this test const result = await slowOperation(); expect(result).toBeDefined();}, 10000); // 10 second timeout