Test infrastructure for JWebMP modules — provides base test classes, SPI-driven lifecycle hooks, and integration-test scaffolding with Vert.x HTTP server smoke-testing.
BaseTest manages Guice context bootstrap and per-test initialisation/teardown; BaseIntegrationTest adds end-to-end HTTP serving and HTML validation. Extension is SPI-driven via ServiceLoader.
Built on GuicedEE · JUnit 5 · Vert.x 5 · Java 25+
<dependency>
<groupId>com.jwebmp.core</groupId>
<artifactId>jwebmp-testlib</artifactId>
<scope>test</scope>
</dependency>Gradle (Kotlin DSL)
testImplementation("com.jwebmp.core:jwebmp-testlib:2.0.0-SNAPSHOT")Version is managed by the JWebMP BOM.
- Guice-aware test lifecycle —
BaseTestbootstraps the Guice injector and runs SPI-discovered initialiser/destroy hooks before and after each test - Three lifecycle SPIs —
ITestInstanceInitializerService,ITestInstanceDestroyService,ITestInstanceResetService— each uses CRTP andIDefaultServicefor sort-ordered, pluggable test setup and teardown - Integration test base —
BaseIntegrationTestspins up a JDKHttpServer, serves your page HTML, fetches it withHttpClient, and asserts HTTP 200, content-type, and basic DOM structure - Component consistency validation — built-in
validateComponentConsistency()checks for<html>,<head>, and<body>elements in rendered output - BrowserStack Local support — optional
BrowserStackLocalExtension(JUnit 5 extension) manages the BrowserStack Local tunnel lifecycle whenBROWSERSTACK_ACCESS_KEYis set - Vert.x HTTP server hook —
BaseIntegrationTestimplementsVertxHttpServerConfiguratorfor use with Vert.x-based server tests - Convenience base classes —
DefaultTestStructurewires@BeforeAll/@AfterAll/@BeforeEach/@AfterEachto the SPI chain so subclasses just write test methods
Extend BaseTest for unit tests — Guice context and SPI hooks are handled automatically:
public class MyComponentTest extends BaseTest {
@Test
public void shouldRenderHeading() {
// Guice injector is already bootstrapped
MyComponent comp = IGuiceContext.get(MyComponent.class);
String html = comp.toString(true);
assertTrue(html.contains("<h1>"));
}
}For integration tests, extend BaseIntegrationTest and supply the HTML to serve:
public class MyPageIT extends BaseIntegrationTest {
@Override
protected String htmlSupplier() {
IPage<?> page = IGuiceContext.get(IPage.class);
return page.toString(true);
}
@Test
public void smokeTest() throws Exception {
runHttpServerSmoke("My App Title");
}
}@BeforeAll
└─ IBaseTest.initializeAll() (redirect stderr → stdout)
@BeforeEach
└─ BaseTest.initialize()
└─ ServiceLoader<ITestInstanceInitializerService> (sorted by sortOrder)
└─ each.initialize(testInstance)
── test method runs ──
@AfterEach
└─ BaseTest.tearDown()
└─ ServiceLoader<ITestInstanceDestroyService> (sorted by sortOrder)
└─ each.destroy(testInstance)
@AfterAll
└─ IBaseTest.tearDownAll()
@BeforeAll
└─ GuiceContext.instance().inject() (full Guice bootstrap)
@Test
└─ runHttpServerSmoke(mustContainText)
├─ Start JDK HttpServer on random port
├─ Serve htmlSupplier() at "/"
├─ Fetch with HttpClient → assert HTTP 200 + text/html
├─ Assert body contains mustContainText
├─ validateComponentConsistency(html)
├─ maybeValidateWithBrowserStackSDK(url, response)
└─ Stop server
All SPIs are discovered via ServiceLoader. Register implementations with JPMS provides...with or META-INF/services.
Runs before each test. Use it to seed data, reset caches, or configure the Guice context:
public class SeedTestData
implements ITestInstanceInitializerService<SeedTestData> {
@Override
public void initialize(BaseTest testInstance) {
// insert test fixtures, reset in-memory stores, etc.
}
@Override
public Integer sortOrder() {
return 10; // run early
}
}Runs after each test. Use it to clean up resources:
public class CleanupTestData
implements ITestInstanceDestroyService<CleanupTestData> {
@Override
public void destroy(BaseTest testInstance) {
// drop temp tables, close connections, etc.
}
}Called by BaseTest.reset() for a full teardown → re-initialise cycle mid-test:
public class ResetGuiceContext
implements ITestInstanceResetService<ResetGuiceContext> {
@Override
public void reset(BaseTest testInstance) {
// force-rebuild the injector, clear singletons, etc.
}
}com.jwebmp.core:jwebmp-testlib
├── com.guicedee:inject (Guice injector bootstrap)
├── com.guicedee:web (Vert.x HTTP server for integration tests)
├── org.junit.jupiter:junit-jupiter-api (JUnit 5, compile scope)
├── com.guicedee.modules.services:uadetector-core
├── com.guicedee.modules.services:uadetector-resources
├── org.apache.commons:commons-lang3
├── org.apache.commons:commons-text
└── commons-io:commons-io
| Class | Role |
|---|---|
BaseTest |
JUnit 5 base — @BeforeEach/@AfterEach bootstrap Guice and run SPI hooks |
IBaseTest |
Interface — @BeforeAll/@AfterAll static hooks, reset()/initialize()/tearDown() contract |
DefaultTestStructure |
Convenience subclass of BaseTest — wires all lifecycle annotations |
BaseIntegrationTest |
Abstract integration test — JDK HttpServer smoke-testing, Vert.x server hook, HTML validation |
BrowserStackLocalExtension |
JUnit 5 extension — manages BrowserStack Local tunnel lifecycle (optional, disabled without access key) |
ITestInstanceInitializerService |
SPI — @FunctionalInterface — runs before each test |
ITestInstanceDestroyService |
SPI — @FunctionalInterface — runs after each test |
ITestInstanceResetService |
SPI — @FunctionalInterface — full reset cycle |
Issues and pull requests are welcome — please add tests for new SPI implementations or test infrastructure changes.