-
Notifications
You must be signed in to change notification settings - Fork 1
Testing
QQQ enforces strict testing standards to ensure framework quality and reliability. This guide covers testing strategies, tools, and requirements for QQQ framework development.
QQQ treats testing as a quality gate, not an afterthought:
# Testing is integrated into the build process
mvn clean install # Runs tests + coverage + validation
mvn test # Just tests
mvn verify # Tests + coverage checksCore Principles:
- Test-Driven Development: Write tests before or alongside code
- Comprehensive Coverage: 80% instruction, 95% class coverage required
- Real Testing: Use actual QQQ components, not mocks
- Integration Focus: Test how components work together
QQQ follows a balanced testing approach:
/\
/ \ E2E Tests (Sample Project)
/____\
/ \ Integration Tests (Cross-module)
/________\
Unit Tests (Individual components)
QQQ uses modern Java testing tools:
- JUnit 5: Modern testing framework with lifecycle hooks
- AssertJ: Fluent assertions for readable test code
- JaCoCo: Code coverage analysis and enforcement
- Maven Surefire: Test execution and reporting
QQQ provides comprehensive testing infrastructure:
// β
CORRECT - Extending QQQ's BaseTest
public class MyModuleTest extends BaseTest
{
@Test
void testMyFeature()
{
// BaseTest provides:
// - QContext with test QInstance
// - Memory backend for isolated testing
// - Test session and user setup
// - Automatic cleanup after each test
// Your test logic here
}
}QQQ enforces coverage requirements that must be met:
<coverage.haltOnFailure>true</coverage.haltOnFailure>
<coverage.instructionCoveredRatioMinimum>0.80</coverage.instructionCoveredRatioMinimum>
<coverage.classCoveredRatioMinimum>0.95</coverage.classCoveredRatioMinimum>Coverage Rules:
- Instructions: 80% minimum (build fails if below)
- Classes: 95% minimum (build fails if below)
- Lines: Monitored but not enforced
- Branches: Monitored but not enforced
Coverage is checked automatically:
# Check coverage without failing build
mvn jacoco:report
# Full build with coverage enforcement
mvn clean install
# Coverage report location
open target/site/jacoco/index.htmlTest individual components in isolation:
@Test
void testActionExecution()
{
// Test action logic
MyAction action = new MyAction();
MyInput input = new MyInput("test");
MyOutput output = action.execute(input);
// Verify results
assertThat(output.getResult()).isEqualTo("expected");
}Test how components work together:
@Test
void testBackendIntegration()
{
// Test backend module with QQQ core
QInstance instance = TestUtils.defineInstance();
instance.addBackend(new RDBMSBackend());
// Verify integration
assertThat(instance.getBackends()).hasSize(1);
}Test QQQ framework extensions:
@Test
void testNewMetadataType()
{
// Test new metadata integration
QInstance instance = TestUtils.defineInstance();
instance.addMetaData(new MyNewMetaData());
// Verify metadata is properly integrated
assertThat(instance.getMetaData(MyNewMetaData.class)).isNotNull();
}QQQ provides utilities for test data:
// Create test QInstance
QInstance instance = TestUtils.defineInstance();
// Create test session
QSession session = TestUtils.newSession();
// Create test records
QRecord record = TestUtils.createRecord("person", Map.of("name", "John"));Use in-memory storage for isolated testing:
@Test
void testWithMemoryBackend()
{
// Memory backend provides isolated storage
QInstance instance = TestUtils.defineInstance();
instance.addBackend(new MemoryBackend());
// Tests run in isolation
// No external dependencies
// Fast execution
}Organize tests to match source structure:
src/test/java/
βββ com/kingsrook/qqq/
β βββ actions/
β β βββ MyActionTest.java
β βββ models/
β β βββ MyModelTest.java
β βββ modules/
β βββ MyModuleTest.java
Follow QQQ test naming patterns:
// Test class names
public class MyActionTest extends BaseTest
public class MyModuleIntegrationTest extends BaseTest
// Test method names
@Test
void testActionExecution()
@Test
void testActionWithInvalidInput()
@Test
void testActionIntegration()Test framework performance under load:
@Test
void testConcurrentActionExecution()
{
// Test multiple concurrent actions
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future<MyOutput>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++)
{
futures.add(executor.submit(() -> action.execute(input)));
}
// Verify all actions complete successfully
futures.forEach(future -> assertThat(future.get()).isNotNull());
}Monitor memory usage in tests:
@Test
void testMemoryUsage()
{
// Monitor memory before
long memoryBefore = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
// Execute action
action.execute(input);
// Monitor memory after
long memoryAfter = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
// Verify reasonable memory usage
assertThat(memoryAfter - memoryBefore).isLessThan(10 * 1024 * 1024); // 10MB
}Run tests during development:
# Run all tests
mvn test
# Run specific module tests
mvn test -pl qqq-backend-core
# Run specific test class
mvn test -Dtest=MyActionTest
# Run specific test method
mvn test -Dtest=MyActionTest#testActionExecutionTests run automatically in CI:
# CircleCI runs tests on every commit
# Coverage is enforced
# Build fails if coverage drops below thresholds# Coverage failure
mvn jacoco:report # Check coverage report
# Test timeout
mvn test -Dtest.timeout=300 # Increase timeout
# Memory issues
mvn test -Dtest.maxMemory=2g # Increase memory# Run with debug output
mvn test -X
# Run single test with debug
mvn test -Dtest=MyActionTest -DtestOutputToFile=false
# Check test output files
ls -la target/surefire-reports/- Arrange-Act-Assert: Structure tests clearly
- Test Names: Use descriptive test method names
- Single Responsibility: Each test verifies one thing
- Real Data: Use realistic test data
- Keep Tests Fast: Tests should run quickly
- Isolate Tests: Tests should not depend on each other
- Clean Setup: Use @BeforeEach and @AfterEach properly
- Update Tests: Keep tests current with code changes
For development setup, see Developer Onboarding. For code standards, see Code Review Standards. For build process, see Building Locally.
QQQ is a powerful, open source, metadata-driven application framework designed specifically for engineers who want to build business applications quickly without starting from scratch.
Built by Kingsrook - making engineers more productive through intelligent automation and developer tools.
- π Wiki Home - Start here for comprehensive guides
- π GitHub Repository - Source code and issues
- π¦ Maven Central - Download artifacts
- π’ Kingsrook Website - Company information
- π§ Building Locally - Build QQQ from source
- π¨βπ» Developer Onboarding - Setup development environment
- ποΈ High-Level Architecture - Understand QQQ's design
- π¦ Core Modules - Available components and usage
- π Contribution Guidelines - How to contribute
- π Code Review Standards - Coding standards
- π§ͺ Testing Guide - Testing requirements and strategy
- π Feature Development - How to extend QQQ
- π Release Flow - Release process and workflow
- π·οΈ Semantic Versioning - Versioning policy
- π Public API Overview - API documentation
- π§ Compatibility Matrix - Version compatibility
- β FAQ - Frequently asked questions
- π¨ Common Errors - Troubleshooting guide
- π¬ GitHub Issues - Report bugs and request features
- π¬ GitHub Discussions - Ask questions and get help
- π License - GNU Affero General Public License v3.0
- π Security Policy - Report security vulnerabilities
- π Code of Conduct - Community standards
- π§ Contact - General inquiries
- π Security - Security issues
QQQ is 100% open source - you have complete ownership and control. No vendor lock-in, no SaaS subscriptions, just full control over your code, data, and system. π
This footer appears on all wiki pages. For the most up-to-date information, always check the GitHub repository.