🧪 08_PLUGINS Testing Strategy¶
📍 Testing Framework Location¶
NO creamos testing framework aquí. Ya existe en:
Este documento explica cómo usar ese framework para validar cada componente de 08_PLUGINS.
🎯 Testing Philosophy para Plugin Infrastructure¶
Principios Fundamentales¶
- Test-Driven Development (TDD): Escribir tests ANTES que implementación
- Validación Continua: Cada carpeta tiene tests que demuestran que funciona
- Automated Quality Gates: CI/CD ejecuta todos los tests
- Documentation Through Tests: Tests son ejemplos vivientes de uso
📂 Testing por Carpeta¶
08_00_00_contracts (Interfaces Base)¶
¿Qué testear? - ✅ Headers compilan sin errores - ✅ Interfaces son abstractas puras (no instanciables) - ✅ Documentación completa por método - ✅ Ejemplo de implementación compila
Ubicación tests:
2 - FOUNDATION/03_INFRA/03_04_testing_framework/tests/integration/08_plugins/
└── test_00_contracts.cpp
Ejemplo test:
TEST_CASE("IPluginProcessor interface is pure virtual", "[contracts][unit]") {
// Verify cannot instantiate
// IPluginProcessor processor; ← Should not compile
REQUIRE(std::is_abstract<IPluginProcessor>::value);
}
TEST_CASE("Concrete implementation compiles", "[contracts][integration]") {
class TestProcessor : public IPluginProcessor {
void process(AudioBuffer& buffer) override { /* impl */ }
void initialize(float sampleRate, int blockSize) override { /* impl */ }
};
TestProcessor processor;
SUCCEED("Concrete implementation compiled and instantiated");
}
08_01_00_component_library (Catálogo L3)¶
¿Qué testear? - ✅ Catálogo JSON válido (schema compliance) - ✅ Todos los L3s referenciados existen en 05_MODULES - ✅ Metadata completa por componente - ✅ Search functionality funciona
Tests:
TEST_CASE("Component catalog is valid JSON", "[composition][unit]") {
auto catalog = loadJson("component_library/catalog.json");
REQUIRE(catalog.is_object());
REQUIRE(catalog.contains("components"));
}
TEST_CASE("All referenced L3 engines exist", "[composition][integration]") {
auto catalog = ComponentCatalog::load();
for (const auto& component : catalog.components()) {
INFO("Checking component: " << component.name);
// Verify L3 exists in 05_MODULES
std::filesystem::path l3Path =
"../../3 - COMPONENTS/05_MODULES/" + component.path;
REQUIRE(std::filesystem::exists(l3Path));
}
}
08_02_00_engine_instantiation (DSP Factory)¶
¿Qué testear? - ✅ Factory crea instancias válidas de L3s - ✅ Dependency resolution correcto - ✅ Resource allocation sin memory leaks - ✅ Initialization order respetado
Tests:
TEST_CASE("Factory instantiates L3 engine", "[dsp][integration]") {
EngineFactory factory;
auto engine = factory.create("BiquadFilter", "v1.0");
REQUIRE(engine != nullptr);
REQUIRE(engine->getName() == "BiquadFilter");
REQUIRE(engine->getVersion() == "v1.0");
}
TEST_CASE("Factory respects dependencies", "[dsp][integration]") {
EngineFactory factory;
// Compressor depends on EnvelopeFollower
auto compressor = factory.create("Compressor", "v1.0");
REQUIRE(compressor != nullptr);
REQUIRE(compressor->getDependencies().size() > 0);
// Verify dependencies were initialized
for (const auto& dep : compressor->getDependencies()) {
REQUIRE(dep->isInitialized());
}
}
08_07_00_syntax_validation (Manifest Validation)¶
¿Qué testear? - ✅ Valid manifests pass validation - ✅ Invalid manifests fail with clear errors - ✅ Schema compliance checking - ✅ Helpful error messages
Tests:
TEST_CASE("Valid manifest passes validation", "[validation][unit]") {
const char* validManifest = R"({
"product": "TestPlugin",
"type": "l4_plugin",
"engines": [
{"id": "filter", "type": "BiquadFilter", "version": "1.0"}
],
"routing": {
"signal": "input → filter → output"
}
})";
ManifestValidator validator;
auto result = validator.validate(validManifest);
REQUIRE(result.isValid());
REQUIRE(result.errors().empty());
}
TEST_CASE("Invalid manifest fails with clear error", "[validation][unit]") {
const char* invalidManifest = R"({
"product": "TestPlugin",
"type": "invalid_type"
})";
ManifestValidator validator;
auto result = validator.validate(invalidManifest);
REQUIRE_FALSE(result.isValid());
REQUIRE(result.errors().size() > 0);
// Verify error message is helpful
auto error = result.errors()[0];
REQUIRE(error.contains("invalid_type"));
REQUIRE(error.contains("l4_plugin or l5_suite"));
}
🔄 Testing Workflow¶
Paso 1: Definir SPEC¶
Antes de implementar, crear SPEC.md en cada carpeta:
# 08_00_00_contracts Specification
## Purpose
Define abstract interfaces for all plugins.
## Requirements
- IPluginProcessor with process(), initialize(), shutdown()
- IStateManager with saveState(), loadState()
- Pure virtual (= 0) methods only
## Acceptance Criteria
✅ Headers compile
✅ Cannot instantiate interfaces
✅ Concrete impl compiles
✅ All methods documented
Paso 2: Escribir Tests (RED)¶
Crear tests que fallan (aún no hay implementación):
TEST_CASE("IPluginProcessor compiles", "[contracts]") {
// This will FAIL initially - header doesn't exist yet
#include "IPluginProcessor.hpp"
SUCCEED();
}
Paso 3: Implementar (GREEN)¶
Crear implementación mínima que pasa tests:
// IPluginProcessor.hpp
class IPluginProcessor {
public:
virtual ~IPluginProcessor() = default;
virtual void process(AudioBuffer& buffer) = 0;
virtual void initialize(float sampleRate, int blockSize) = 0;
};
Paso 4: Refinar (REFACTOR)¶
Mejorar implementación, tests siguen pasando:
Paso 5: Validar¶
# Run all tests
cd "2 - FOUNDATION/03_INFRA/03_04_testing_framework"
cmake --build build --target RUN_TESTS
# Or specific category
./build/Release/audiolab_tests [contracts]
📊 Coverage Requirements¶
Por Categoría¶
| Carpeta | Unit Tests | Integration Tests | System Tests |
|---|---|---|---|
| 08_00_contracts | 100% | N/A | N/A |
| 08_01_composition_tools | 80% | 90% | 100% |
| 08_02_dsp_integration | 70% | 90% | N/A |
| 08_07_manifest_validation | 95% | 100% | N/A |
| 08_13_products | N/A | 80% | 100% |
🎯 Quality Gates¶
Pre-Commit¶
Pre-Push¶
CI Pipeline¶
📝 Test Naming Convention¶
Seguir patrón de 03_INFRA/03_04_testing_framework:
// Pattern: [Component] [action] [expected result]
TEST_CASE("Biquad filter attenuates frequencies above cutoff", "[dsp][unit]")
TEST_CASE("Manifest validator rejects invalid routing", "[validation][unit]")
TEST_CASE("Plugin loads in VST3 host without crash", "[plugin][system]")
Tags Standardizados¶
[unit]- Unit test (< 1ms)[integration]- Integration test (< 100ms)[system]- System test (< 5s)[benchmark]- Performance test[quality]- Audio quality test[regression]- Regression test for fixed bugs
🚀 Getting Started¶
1. Leer filosofía existente¶
code "2 - FOUNDATION/03_INFRA/03_04_testing_framework/03_04_00_test_frameworks/TEST_FRAMEWORK_PHILOSOPHY.md"
2. Ver ejemplos¶
3. Crear primer test¶
# Para 08_00_00_contracts:
cd "2 - FOUNDATION/03_INFRA/03_04_testing_framework"
mkdir -p tests/integration/08_plugins
# Crear test_00_contracts.cpp
💡 Best Practices¶
DO ✅¶
- Escribir tests ANTES de implementar
- Usar helpers existentes de
03_04_02_test_utilities - Mantener tests rápidos (< 1ms unit, < 100ms integration)
- Tests independientes (pueden correr en paralelo)
- Nombres descriptivos y claros
DON'T ❌¶
- Tests que dependen de orden de ejecución
- Tests flaky (non-deterministic)
- Tests mega (testing too much)
- Ignorar tests que fallan
- Commit code sin tests
🔗 Referencias¶
- Framework Philosophy:
03_INFRA/03_04_testing_framework/03_04_00_test_frameworks/TEST_FRAMEWORK_PHILOSOPHY.md - Test Categories:
03_INFRA/03_04_testing_framework/03_04_01_test_organization/TEST_CATEGORIES.md - Test Utilities:
03_INFRA/03_04_testing_framework/03_04_02_test_utilities/ - Catch2 Docs: https://github.com/catchorg/Catch2
Generated with AudioLab 🎵 Testing makes perfect