Skip to content

Commit 283a90f

Browse files
authored
Added testing guidelines section to the CONTRIBUTING.md (#61)
## Summary <!-- Provide a brief description of the story behind this PR, as if explaining to a non-technical person. Or to an LLM so it can learn from it for future (autonomous) code improvements. Feel free to point to a deeper design doc, if applicable. --> Added instructions for what tests should look like and how they should be implemented. This should help all developers working on this project to use consistent testing schema. ## Connected Issues <!-- Have you cared to connect this PR to a work item in DevRev, so that we can understand future routing and attribution? --> - [#ISS-202840](https://app.devrev.ai/devrev/works/ISS-202840)
1 parent 8f00a41 commit 283a90f

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

CONTRIBUTING.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,131 @@ We follow Semantic Versioning (SemVer) for versioning, with the format `MAJOR.MI
99
- `MAJOR` - Breaking changes, incompatible API changes
1010
- `MINOR` - New features, backward compatible
1111
- `PATCH` - Bug fixes, no new features
12+
13+
## Testing
14+
15+
All new code must include comprehensive tests. Follow these testing guidelines:
16+
17+
### Test File Structure
18+
19+
- Test files must be named the same as the file containing the logic, but ending in `.test.ts`
20+
- Example: `user-service.ts``user-service.test.ts`
21+
- Place test files in the same directory as the source files
22+
23+
### Test Organization
24+
25+
Tests should be organized using `describe` and `it` blocks:
26+
27+
```typescript
28+
describe(MyClass.name, () => {
29+
it('should perform expected behavior when given valid input', () => {
30+
// Test implementation
31+
});
32+
33+
it('should handle specific scenario correctly', () => {
34+
// Test implementation
35+
});
36+
37+
it('[edge] should handle null input appropriately', () => {
38+
// Edge case test
39+
});
40+
41+
it('[edge] should handle undefined input appropriately', () => {
42+
// Edge case test
43+
});
44+
});
45+
```
46+
47+
### Test Naming Conventions
48+
49+
- **Describe blocks**: Name after the symbol being tested (class, function, etc.). Use the symbol's `.name` property when available instead of hardcoding the name (e.g., `MyClass.name` instead of `'MyClass'`)
50+
- **It blocks**: Write descriptive test names that start with "should" and describe the expected behavior
51+
- **Edge cases**: Prefix edge case tests with `[edge]` tag (e.g., `it('[edge] should handle null input...')`)
52+
53+
### Test Guidelines
54+
55+
1. **Single Responsibility**: Each test should verify only one specific behavior or outcome
56+
2. **Descriptive Names**: Test names should clearly describe what functionality is being tested
57+
3. **Behavior Testing**: Tests should verify behavior, not implementation details
58+
4. **Edge Cases**: Handle `null`, `undefined`, and other edge cases using the `[edge]` tag prefix
59+
5. **Simplicity**: Keep tests simple and easy to understand
60+
6. **Clarity over Brevity**: Prioritize easily understandable tests over small tests. Tests typically represent 60-70% of a software project's source code, so clarity is essential
61+
7. **Avoid Unnecessary Abstractions**: Minimize abstractions in tests unless absolutely necessary, as they add complexity and make it harder to understand the test steps
62+
8. **AAA Pattern**: Follow the Arrange, Act, Assert pattern for test structure:
63+
- **Arrange**: Set up test data, dependencies, and initial state
64+
- **Act**: Execute the function or method being tested
65+
- **Assert**: Verify the expected outcome or behavior
66+
67+
### Testing Scope and Focus
68+
69+
**Primary Focus: Public Interfaces**
70+
- Tests should primarily focus on testing public-facing (exported) interfaces and APIs
71+
- Test the behavior that external consumers of your code will experience
72+
- This ensures that breaking changes to public contracts are caught by tests
73+
74+
**Internal Logic Testing**
75+
- Be pragmatic about testing internal logic when it provides significant value
76+
- Internal APIs used globally across the application may warrant dedicated test files
77+
- Example: `metrics.spec.ts` tests the public endpoint controller, while `metrics.interceptor.spec.ts` tests internal API used globally
78+
- You can rename or move test files later if they organically outgrow their original scope or no longer fit together
79+
80+
### Example
81+
82+
```typescript
83+
describe(Calculator.name, () => {
84+
it('should add two positive numbers correctly', () => {
85+
// Arrange
86+
const calculator = new Calculator();
87+
const firstNumber = 2;
88+
const secondNumber = 3;
89+
const expectedResult = 5;
90+
91+
// Act
92+
const result = calculator.add(firstNumber, secondNumber);
93+
94+
// Assert
95+
expect(result).toBe(expectedResult);
96+
});
97+
98+
it('should add negative numbers correctly', () => {
99+
// Arrange
100+
const calculator = new Calculator();
101+
const firstNumber = -2;
102+
const secondNumber = -3;
103+
const expectedResult = -5;
104+
105+
// Act
106+
const result = calculator.add(firstNumber, secondNumber);
107+
108+
// Assert
109+
expect(result).toBe(expectedResult);
110+
});
111+
112+
it('[edge] should handle null input by throwing an error', () => {
113+
// Arrange
114+
const calculator = new Calculator();
115+
const nullValue = null;
116+
const validNumber = 5;
117+
118+
// Act & Assert
119+
expect(() => calculator.add(nullValue, validNumber)).toThrow();
120+
});
121+
122+
it('[edge] should handle undefined input by throwing an error', () => {
123+
// Arrange
124+
const calculator = new Calculator();
125+
const undefinedValue = undefined;
126+
const validNumber = 5;
127+
128+
// Act & Assert
129+
expect(() => calculator.add(undefinedValue, validNumber)).toThrow();
130+
});
131+
});
132+
```
133+
134+
### Test Quality
135+
136+
- Tests should fail when the expected behavior breaks
137+
- Test reports should clearly indicate which functionality is affected
138+
- Multiple related assertions can be grouped in the same test if they verify the same behavior
139+
- Always mark edge cases with the `[edge]` tag prefix to distinguish them from main functionality tests

0 commit comments

Comments
 (0)