Testing Guide: Overview
Contents:
Introduction
Welcome to our Testing Guide! This document provides an overview of our approach to unit testing in our development process. Testing is a critical part of software development, ensuring that our code not only works as expected but also remains stable and reliable over time. In this guide, we'll cover the basics of unit testing and the principles that drive our testing strategies.
Unit Testing Basics
Unit testing involves isolating the smallest parts of the application, often individual functions or methods, and testing them independently to ensure they perform as expected. The key to effective unit testing is to cover both expected and unexpected use cases, ensuring that the component behaves correctly in all scenarios.
Principles of Unit Testing
- Isolation: Each test should cover a single "unit" of code, which means the test should not be affected by external factors like network status, database state, etc.
- Repeatability: Tests should yield the same results every time they are run, regardless of environment or timing.
- Automatability: Tests should be automated, enabling them to be run frequently without manual intervention.
- Coverage: Aim for comprehensive coverage, ensuring all critical paths and edge cases are tested.
The Arrange-Act-Assert Model
A fundamental model in unit testing is the Arrange-Act-Assert (AAA) pattern. This pattern provides a clear structure for writing tests:
- Arrange: Set up the testing environment. Initialize objects, variables, mock dependencies, etc.
- Act: Execute the code/unit being tested.
- Assert: Verify that the action of the code produced the expected result.
Examples of AAA
C# and XUnit
using Xunit;
public class CalculatorTests
{
[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Add(5, 3);
// Assert
Assert.Equal(8, result);
}
}
public class Calculator
{
public int Add(int number1, int number2)
{
return number1 + number2;
}
}
Angular and Jasmine
// Example component
export class CalculatorComponent {
add(number1: number, number2: number): number {
return number1 + number2;
}
}
// Test
describe("CalculatorComponent", () => {
let component: CalculatorComponent;
beforeEach(() => {
component = new CalculatorComponent();
});
it("should add two numbers correctly", () => {
// Arrange
let number1 = 5;
let number2 = 3;
// Act
let result = component.add(number1, number2);
// Assert
expect(result).toBe(8);
});
});
In this example, we're testing a simple Add method. The 'Arrange' step creates an instance of the Calculator class, the 'Act' step calls the Add method with parameters, and the 'Assert' step verifies that the output is as expected.
Test-Driven Development (TDD)
We encourage the use of Test-Driven Development (TDD), where tests are written/stubbed before the actual code. This approach ensures that testing is an integral part of the development process and not an afterthought.
Conclusion
This overview provides a basic understanding of the SRP approach to unit testing. For more specific guidelines and examples related to the technologies we use (e.g., Angular, .NET), please refer to the respective sections in this guide.
Happy testing!