alias |
---|
Testing |
- Test specific low level units of functionality in isolation from other units.
- Typically functions or classes.
- More unit tests are written compared to other types.
import React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';
test('renders the correct data', () => {
const { getByText } = render(<MyComponent data="test data" />);
expect(getByText('test data')).toBeInTheDocument();
});
test('renders the default data when no prop is provided', () => {
const { getByText } = render(<MyComponent />);
expect(getByText('Default Text')).toBeInTheDocument();
});
- Ensure the individual pieces of the application work well together.
- Focuses on catching flaws in interactions between integrated units or components.
- Strikes a balance between unit and end-to-end tests, providing confidence in how components work together.
- More integration tests are written compared to E2E tests.
// ParentComponent.js
function ParentComponent({ data }) {
return <ChildComponent data={data} />;
}
// ParentComponent.test.js
import React from 'react';
import { render } from '@testing-library/react';
import ParentComponent from './ParentComponent';
test('renders the correct data from the child component', () => {
const { getByText } = render(<ParentComponent data="test data" />);
expect(getByText('test data')).toBeInTheDocument();
});
test('renders the default data from the child component when no prop is provided', () => {
const { getByText } = render(<ParentComponent />);
expect(getByText('Default Child Data')).toBeInTheDocument();
});
- Ensure application works well from the user's perspective.
- Ensures proper communication with other systems, interfaces, and databases.
- Takes more time and can be expensive in terms of efficiency, time, and money.
- Less E2E tests are written compared to other types.
// App.jsx
function App() {
const [count, setCount] = useState(0);
return (<div>
<h1>Counter App</h1>
<p data-testid="count">Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>);
}
export default App;
// e2e.test.js
import { test, expect } from '@playwright/test';
test('counter increments when the button is clicked', async ({ page }) => {
// Navigate to the app
await page.goto('http://localhost:3000');
// Check the initial count
const countElement = page.locator('[data-testid="count"]');
await expect(countElement).toHaveText('Count: 0');
// Click the increment button
await page.click('text=Increment');
// Check if the count has been incremented
await expect(countElement).toHaveText('Count: 1');
// Click the increment button again
await page.click('text=Increment');
// Check if the count has been incremented again
await expect(countElement).toHaveText('Count: 2');
});
-
Involves creating simulated objects or functions to replace real dependencies in tests.
-
Allows to test a specific piece of code without worrying about how other parts of the system work.
-
Replaces real objects that code depends on with fake objects (called mocks) that simulate the behavior of the real ones.
- These objects can be used to control what happens during the test.
- You can make them return specific values or behave in certain ways.
- These objects can be used to control what happens during the test.
-
Useful for:
- Isolating components for true unit testing
- Simulating API calls and responses
- Testing different scenarios and edge cases
-
Stubs are simple mocks that return pre-programmed responses.
/* --- Code --- */
public interface Temperature {
double getTemperature();
}
public class WeatherService {
private Temperature t;
public WeatherService(Temperature t) {
this.t = t;
}
public String getWeatherDescription() {
double t = t.getTemperature();
if (t < 0) return "Freezing";
if (t < 15) return "Cold";
if (t < 25) return "Warm";
return "Hot";
}
public boolean isTemperatureAboveThreshold(double threshold) {
return t.getTemperature() > threshold;
}
}
/* --- Test --- */
@Test
public void testWeatherDescription() {
// Create a stub
Temperature t = new Temperature() {
@Override
public double getTemperature() {
return 20.0; // Always return 20 degrees
}
};
WeatherService service = new WeatherService(t);
assertEquals("Warm", service.getWeatherDescription());
}
- Mocks are more sophisticated than stubs, these can be programmed with expectations about how they should be called.
@Test
public void testIsTemperatureAboveThresholdWithMock() {
// Create a mock for Temperature
Temperature mockTemp = mock(Temperature.class);
// Set up the mock behavior
when(mockTemp.getTemperature()).thenReturn(30.0);
WeatherService service = new WeatherService(mockTemp);
assertTrue(service.isTemperatureAboveThreshold(25.0));
// Verify that getTemperature was called exactly once
verify(mockTemp, times(1)).getTemperature();
}
-
3 classes of testing tools
- Testing environment / test runners
- collect test & run test code
- e.g. Jest, Vitest, Playwright
- Test frameworks
- define / organize individual tests.
- e.g. Testing Library
- Assertion libraries
- create testable claims
- Testing environment / test runners
-
Common testing tools fall into at least 2 of the above classes.
[!quote]- The Testing Trophy
-
The goal of TDD is code quality.
-
Advantages
- Clarified thinking / code design
- Better communication between developers
- Better structure / organization of production code
-
Disadvantages
- Takes longer initially
- Bad tests create a fall sense of security
- Good tests should be:
- ==R==eadable
- ==I==solated - test run independent of one another
- ==T==horough - cover all edge cases
- ==E==xplicit
- A structured approach to writing test cases that ensures clarity and separation of concerns.
- Widely used in unit testing and follows three distinct phases:
- Arrange: Set up the necessary conditions and inputs for the test.
- Act: Execute the functionality being tested.
- Assert: Verify that the outcome is as expected.
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('increments counter on button click', () => {
// Arrange
render(<Counter />);
// Act
fireEvent.click(screen.getByText('Increment'));
// Assert
expect(screen.getByText('Counter: 1')).toBeInTheDocument();
});
- BDD
- Mock Tests
- WebDriver protocol
- Smoke Tests
- Regression Tests
- Visual Tests
- API Testing
- Jest
- Vitest
- Mocha
- Chai
- QUnit
- Jasmine
- Cypress
- Enzyme
- Playwright
- Testing Library