Let's consider a more complex example involving a user authentication feature in a web application.
In TDD, we focus on writing tests that describe the behavior of the system from a technical perspective, typically starting with low-level unit tests and gradually moving towards higher-level integration tests.
// authentication.test.js
import { authenticateUser } from './authentication';
describe('Authentication', () => {
test('returns a user object if authentication is successful', () => {
// Mock user credentials
const credentials = {
username: 'john_doe',
password: 'password123',
};
const user = authenticateUser(credentials);
expect(user).toBeDefined();
expect(user.username).toBe('john_doe');
expect(user.token).toBeDefined();
});
test('throws an error if authentication fails', () => {
// Mock invalid user credentials
const credentials = {
username: 'invalid_user',
password: 'invalid_password',
};
expect(() => {
authenticateUser(credentials);
}).toThrow('Authentication failed');
});
});
// authentication.js
export function authenticateUser(credentials) {
// Implementation logic to authenticate user
}
In BDD, we focus on describing the behavior of the system using natural language constructs that are closer to the language used by stakeholders.
// authentication.test.js
import { authenticateUser } from './authentication';
describe('User Authentication', () => {
describe('Successful authentication', () => {
it('should return a user object with a valid token', () => {
// Mock user credentials
const credentials = {
username: 'john_doe',
password: 'password123',
};
const user = authenticateUser(credentials);
expect(user).toBeDefined();
expect(user.username).toBe('john_doe');
expect(user.token).toBeDefined();
});
});
describe('Failed authentication', () => {
it('should throw an error if invalid credentials are provided', () => {
// Mock invalid user credentials
const credentials = {
username: 'invalid_user',
password: 'invalid_password',
};
expect(() => {
authenticateUser(credentials);
}).toThrow('Authentication failed');
});
});
});
// authentication.js
export function authenticateUser(credentials) {
// Implementation logic to authenticate user
}
In this example, you can see that the difference lies in the language used to describe the behavior. In the TDD approach, the test descriptions might focus more on technical aspects like "returns a user object if authentication is successful", whereas in the BDD approach, the descriptions are more high-level and user-centric like "should return a user object with a valid token".