Testing Strategy
Overview: This document describes the testing philosophy, goals, scope, and approach for the StockEase backend.
Table of Contents
- Testing Goals
- Testing Philosophy
- Scope: In Scope
- Scope: Out of Scope
- Test Levels
- Success Criteria
- Risk Mitigation
- Related Documentation
Testing Goals
Primary Goals
| Goal | Rationale | Metric |
|---|---|---|
| Correctness | Ensure APIs return correct data and business logic works | Pass rate 100% on PR merge |
| Safety | Catch regressions early before production | Coverage β₯ 70% line, β₯ 60% branch |
| Maintainability | Make tests easy to understand and modify | Clear naming, shared test configs |
| Speed | Enable fast feedback loops during development | Unit tests < 5 sec, all tests < 30 sec |
Secondary Goals
| Goal | Why | Current Status |
|---|---|---|
| Authorization | Verify role-based access works (ADMIN vs USER) | β Implemented in controller tests |
| Data Integrity | Ensure data isnβt corrupted during CRUD operations | β Mocked repository validation |
| API Contract | Prevent breaking changes to REST endpoints | πΆ Manual (OpenAPI spec ready) |
| Performance | Detect performance regressions | β Deferred (no load tests yet) |
Testing Philosophy
Principle 1: Test Behavior, Not Implementation
- Do: Test that
POST /api/productsreturns a product with the correct name - Donβt: Test that the mock was called exactly 3 times
- Tool: Use
assertThat()(AssertJ) oververify()(Mockito) when possible
Principle 2: Test in Isolation
- Each test should be independent and not depend on other tests
- Use
@BeforeEachto reset mocks and state - Tests can run in any order
Example (from
ProductControllerTest.java):
@BeforeEach
void resetMocks() {
Mockito.reset(productRepository, jwtUtil);
Mockito.when(jwtUtil.validateToken(Mockito.anyString())).thenReturn(true);
}Principle 3: Use Appropriate Test Levels
- Unit tests for business logic (services, utils)
- Slice tests for controller endpoints (fast, focused)
- Integration tests for full workflows (slower, rare)
- Avoid: End-to-end UI tests (out of scope for this backend)
Principle 4: Mock External Dependencies
- Mock database repositories to test controller logic in isolation
- Mock
JwtUtilto avoid cryptographic operations - Keep mocks predictable and deterministic
Example (from
AuthControllerTest.java):
@Mock
private JwtUtil jwtUtil;
@Test
void testLoginSuccess() {
when(jwtUtil.generateToken(username, role)).thenReturn(token);
// Test doesn't depend on actual JWT generation
}Principle 5: Use Parameterized Tests for Multiple Scenarios
- One test method can cover multiple input combinations
- Reduces code duplication
- Makes it clear what scenarios are tested
Example (from
ProductControllerTest.java):
@ParameterizedTest
@CsvSource({
"adminUser, ADMIN",
"regularUser, USER"
})
void testLowStockProductsWithRoles(String username, String role) { }Scope: In Scope
β What We Test
1. REST API Endpoints
- Controllers:
AuthController,ProductController - Methods: POST (create), GET (read), PUT (update), DELETE
- Coverage: Happy path, error cases, authorization checks
- Test Classes:
ProductCreateControllerTest,ProductFetchControllerTest, etc.
2. Authentication & Authorization
- JWT token generation and validation
- Role-based access control (ADMIN vs USER)
- Spring Security integration
Test Classes:
AuthControllerTest.java,
ProductCreateControllerTest.java
3. Request/Response Validation
- Input validation (e.g., product name, quantity)
- HTTP status codes (200, 201, 400, 401, 403, 404)
- Response JSON structure
4. Business Logic
- Product CRUD operations
- Inventory calculations
- Role-based permissions
5. Application Bootstrap
- Spring context loads successfully
- All beans are wired correctly
- Configuration properties are applied
Test Class:
StockEaseApplicationTests.java
Scope: Out of Scope
β What We Donβt Test (Yet)
1. End-to-End UI Tests
- Why excluded: Frontend is separate (React/Vite), requires different test stack
- Future: Could be added later with Playwright or Cypress
2. Performance/Load Tests
- Why excluded: Not required for MVP
- Future: Consider JMH or k6 if performance becomes critical
3. Database Layer Tests
- Why excluded: Using H2 in-memory database with mocked repositories
- Note: Repository logic is tested indirectly through controller tests
- Future: Could add @DataJpaTest for specific query methods
4. Integration with External Services
- Why excluded: No external API calls in current codebase
- Note: If added (e.g., payment
gateway), would use
@MockServeror similar
5. Security Vulnerability Scanning
- Why excluded: Handled by OWASP Dependency Check in CI
- Note: Tests focus on functional security, not vulnerability discovery
6. Stress/Chaos Tests
- Why excluded: Not required for MVP
- Future: If high availability is critical, add circuit breaker tests
Test Levels
Level 1: Unit Tests (70%)
Definition: Test a single class or method in isolation with all dependencies mocked.
Examples: - Controller action:
AuthControllerTest.testLoginSuccess() -
Service method: Mock AuthenticationManager,
test login logic
Framework: JUnit 5, Mockito
Execution: < 1 sec per test
Files:
backend/src/test/java/com/stocks/stockease/controller/
Level 2: Slice Tests (25%)
Definition: Test a horizontal slice of the application (e.g., web layer) without the full context.
Pattern: @WebMvcTest β
loads only controllers + security, not
services/repositories
Examples: -
ProductControllerTest β HTTP layer with
MockMvc, repository mocked -
ProductCreateControllerTest β POST endpoint
with authorization checks
Framework: Spring Boot Test,
MockMvc, Mockito
Execution: 1-2 sec per test
Files: Most classes in
backend/src/test/java/com/stocks/stockease/controller/
@WebMvcTest(ProductController.class)
public class ProductFetchControllerTest {
@Autowired private MockMvc mockMvc;
@MockitoBean private ProductRepository productRepository; // Mocked!
@Test
void testGetProducts() throws Exception {
mockMvc.perform(get("/api/products")
.with(SecurityMockMvcRequestPostProcessors.user("testUser")))
.andExpect(status().isOk());
}
}Level 3: Integration Tests (5%)
Definition: Test multiple components working together (e.g., controller + service + repository).
Pattern:
@SpringBootTest β loads full application
context
Examples: -
StockEaseApplicationTests.contextLoads() β
verify all beans wire correctly
Framework: Spring Boot Test
Execution: 3-5 sec per test
Files:
backend/src/test/java/com/stocks/stockease/
@SpringBootTest
@ActiveProfiles("test")
class StockEaseApplicationTests {
@Test
void contextLoads() {
// Spring has successfully loaded all beans
}
}Level 4: System/E2E Tests (Future)
Not implemented yet β Would require: - Full stack: frontend + backend + database - Browser automation (Playwright, Cypress) - Test data setup across layers - ~30 seconds per test
Success Criteria
Build-Time Criteria (Automated)
- β
All 65+ tests pass:
mvn clean test - β No compilation errors
- β Line coverage β₯ 70%
- β Branch coverage β₯ 60%
Code Review Criteria (Manual)
- β New tests for new functionality
- β Clear, descriptive test names
- β No test interdependencies
- β Mocks are appropriate (not over-mocking)
Performance Criteria
- β All tests complete in < 30 seconds
- β Each unit test completes in < 1 second
- β Controller slice tests complete in < 2 seconds
Maintenance Criteria
- β
Tests use shared
TestConfigto avoid duplication - β Test data is consistent across test classes
- β
Mocks are reset in
@BeforeEach
Risk Mitigation
Risk 1: Broken Tests Block Merges
- Mitigation: Run tests locally
before push (
mvn clean test) - Fallback: CI blocks merge if tests fail (GitHub Actions gate)
Risk 2: Tests Become Obsolete
- Mitigation: Update tests when requirements change
- Process: Include test updates in code review checklist
Risk 3: Coverage Gaps Hide Bugs
- Mitigation: Target 70%+ coverage, focus on critical paths
- Tools: JaCoCo report highlights uncovered code
Risk 4: Flaky Tests (Intermittent Failures)
- Mitigation: Use
@BeforeEachto reset state, avoidsleep() - Monitor: Track flaky tests in CI logs
Risk 5: Test Data Inconsistency
- Mitigation: Use
TestConfig.javafor shared mock setup - Benefit: All tests see consistent JWT, SecurityContext
Current Test Coverage
By Layer
| Layer | Tests | Method |
|---|---|---|
| Controller | 8 classes | @WebMvcTest |
| Service | 0 (mocked) | Not tested in isolation |
| Repository | 0 (mocked) | Not tested in isolation |
| Security | 2 classes | JWT validation in controller tests |
| Config | 0 (bootstrapped) | Tested via contextLoads() |
By Feature
| Feature | Tests | Status |
|---|---|---|
| Authentication | 2 | β AuthControllerTest |
| Product CRUD | 7 | β ProductControllerTest, ProductCreateControllerTest, etc. |
| Authorization | 7 | β Role checks in all controller tests |
| Application Bootstrap | 1 | β StockEaseApplicationTests |
Testing Best Practices Applied
β Currently Doing Well
- Clear test names:
testValidProductCreation,testLoginSuccess - Mocking external deps: JwtUtil, AuthenticationManager are mocked
- Using Spring slices: @WebMvcTest keeps tests fast
- Parameterized tests: @ParameterizedTest with @CsvSource
- Isolated test state: @BeforeEach resets mocks
- Shared test config: TestConfig.java for common beans
πΆ Could Improve
- Service layer tests: Add unit tests for business logic (future)
- Test data builders: Create reusable object builders (future)
- API contract tests: Validate OpenAPI schema (future)
- Performance baselines: Add timing assertions (future)
Related Documentation
Testing Topics
- Test Pyramid β Unit/slice/integration breakdown
- Coverage Matrix β Whatβs tested by layer and feature
- Naming Conventions β Test method naming patterns
- Spring Slices β @WebMvcTest and slice test patterns
Implementation Details
- Security Tests β How we test JWT and roles
- Test Data & Fixtures β Mock setup and TestConfig
- Controller Integration Tests β MockMvc patterns
Quality & Metrics
- Coverage & Quality β JaCoCo thresholds, reports
- CI Pipeline Tests β What runs in GitHub Actions
Main Architecture
- Testing Architecture β Entry point for all test docs
- Backend Architecture β System components being tested
- Security Architecture β Authentication & authorization
Last Updated: October 31, 2025
Version: 1.0
Status: β
Reflects current test
implementation