Fork me on GitHub

Quick Reference Guide

1. Add Dependencies


<!-- JUnit 5 (Required for annotation-based testing) -->
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.10.2</version>
  <scope>test</scope>
</dependency>

<!-- For JAX-RS / Page Model API Testing -->
<dependency>
  <groupId>org.bloomreach.forge.brut</groupId>
  <artifactId>brut-resources</artifactId>
  <version>${brut.version}</version>
  <scope>test</scope>
</dependency>

<!-- For Component Testing -->
<dependency>
  <groupId>org.bloomreach.forge.brut</groupId>
  <artifactId>brut-components</artifactId>
  <version>${brut.version}</version>
  <scope>test</scope>
</dependency>
          

Warning: <scope>test</scope> is required. BRUT replaces core HST beans (pipelines, component manager, link creator, etc.) with test-oriented implementations. If BRUT is on the runtime classpath without test scope, its mock beans will shadow production beans and real HST endpoints will stop working.

Note: Most brXM projects already include JUnit 5 via the parent POM.

2. Create Your First Test

JAX-RS API Test (Parameter Injection - Recommended)


package org.example;

import org.bloomreach.forge.brut.resources.annotation.BrxmJaxrsTest;
import org.bloomreach.forge.brut.resources.annotation.DynamicJaxrsTest;
import org.example.rest.HelloResource;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

@BrxmJaxrsTest(resources = {HelloResource.class})  // beanPackages auto-detected!
public class MyApiTest {

    @Test
    void testEndpoint(DynamicJaxrsTest brxm) {  // Parameter injection - no IDE warnings!
        String response = brxm.request()
            .get("/site/api/hello/world")
            .execute();
        assertEquals("Hello, World!", response);
    }
}
          

Page Model API Test


package org.example;

import org.bloomreach.forge.brut.resources.annotation.BrxmPageModelTest;
import org.bloomreach.forge.brut.resources.annotation.DynamicPageModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

@BrxmPageModelTest  // Zero-config for standard project layouts
public class MyPageModelTest {

    @Test
    void testComponent(DynamicPageModelTest brxm) {
        PageModelResponse pageModel = brxm.request()
            .get("/site/resourceapi/news")
            .executeAsPageModel();
        assertNotNull(pageModel.getRootComponent());
    }
}
          

Component Test


package org.example;

import org.bloomreach.forge.brut.components.annotation.BrxmComponentTest;
import org.bloomreach.forge.brut.components.annotation.DynamicComponentTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

@BrxmComponentTest  // beanPackages, nodeTypes auto-detected
public class MyComponentTest {

    @Test
    void testComponent(DynamicComponentTest brxm) {
        assertNotNull(brxm.getHstRequest());
        assertNotNull(brxm.getHstResponse());
        assertTrue(brxm.getRootNode().hasNode("hippo:configuration"));
    }
}
          

Node Type Auto-Detection: When nodeTypes is not specified, types are automatically detected from @Node(jcrType="...") annotations in bean classes. Use explicit nodeTypes only for inheritance ("ns:Child extends ns:Parent") or types outside scanned packages.

Alternative: Field Injection (for @BeforeEach or Nested Classes)


@BrxmJaxrsTest(resources = {HelloResource.class})
public class MyApiTest {

    @SuppressWarnings("unused")  // Injected by extension
    private DynamicJaxrsTest brxm;

    @BeforeEach
    void setup() {
        brxm.getHstRequest().setHeader("X-Custom", "value");
    }

    @Test
    void testEndpoint() {
        brxm.request().get("/site/api/hello").assertBody("Hello");
    }
}
          

3. Configuration Options

JAX-RS Test (Minimal - Zero Config)


@BrxmJaxrsTest(resources = {HelloResource.class, NewsResource.class})
// beanPackages auto-detected from project-settings.xml or pom.xml
          

Full Options (all optional)


@BrxmJaxrsTest(
    // Optional: Override auto-detected bean packages
    beanPackages = {"org.example.model"},

    // JAX-RS resources (recommended - eliminates Spring XML)
    resources = {HelloResource.class},

    // Custom YAML patterns (auto-detected from <package>/imports/)
    yamlPatterns = {"classpath*:custom/**/*.yaml"},

    // Custom CND patterns
    cndPatterns = {"classpath*:custom/**/*.cnd"},

    // Load production HCM content
    loadProjectContent = true,

    // Override auto-detected values
    hstRoot = "/hst:myproject",
    springConfigs = {"/org/example/custom.xml"},
    addonModules = {"/org/example/addon"}
)
          

When to Configure Manually

Use zero-config (recommended) when:

  • Project has project-settings.xml → beanPackages auto-detected
  • Test YAML is in <package>/imports/ → auto-detected
  • HST root matches Maven artifactId → auto-detected

Specify parameters when:

  • beanPackages - auto-detection fails or you need different packages
  • resources - to register JAX-RS endpoints without Spring XML
  • springConfigs - resources need Spring-managed dependencies
  • hstRoot - HST root doesn't match Maven artifactId

@BrxmComponentTest Options


@BrxmComponentTest(
    beanPackages = {"org.example.beans"},
    content = "/test-content.yaml",    // YAML content to import
    contentRoot = "/content/documents", // Where to import + sets site base
    nodeTypes = {"ns:Type extends ns:Base"} // Optional - auto-detected from @Node
)
          

4. Fluent Request API

Basic Requests


@Test
void testWithFluentApi(DynamicJaxrsTest brxm) {
    String response = brxm.request()
        .get("/site/api/news")              // Sets URI and GET method
        .withHeader("X-Custom", "value")    // Add custom header
        .queryParam("category", "tech")     // Add query parameter
        .execute();                         // Execute and get response as String

    assertTrue(response.contains("news"));
}

// One-liner assertion
@Test
void testAssertBody(DynamicJaxrsTest brxm) {
    brxm.request()
        .get("/site/api/hello/world")
        .assertBody("Hello, World!");       // Assert response body directly
}
          

Typed JSON Responses


// JSON deserialization in one line
@Test
void testTypedResponse(DynamicJaxrsTest brxm) {
    User user = brxm.request()
        .get("/site/api/user/123")
        .executeAs(User.class);             // Execute and deserialize JSON

    assertEquals("John", user.getName());
}

// Response with status code
@Test
void testResponseWithStatus(DynamicJaxrsTest brxm) {
    Response<User> response = brxm.request()
        .get("/site/api/users/123")
        .executeWithStatus(User.class);     // Get status + typed body

    assertEquals(200, response.status());
    assertTrue(response.isSuccessful());
    assertEquals("John", response.body().getName());
}
          

POST with JSON Body


// POST with JSON string
@Test
void testPostRequest(DynamicJaxrsTest brxm) {
    User created = brxm.request()
        .post("/site/api/users")
        .withJsonBody("{\"name\": \"John\"}")  // Sets body + Content-Type
        .executeAs(User.class);

    assertEquals("John", created.getName());
}

// POST with object serialization
@Test
void testPostWithObject(DynamicJaxrsTest brxm) {
    User input = new User("Jane", 25);
    User created = brxm.request()
        .post("/site/api/users")
        .withJsonBody(input)                   // Auto-serializes to JSON
        .executeAs(User.class);

    assertEquals("Jane", created.getName());
}
          

Authentication


// Authenticated user with roles
@Test
void testProtectedEndpoint(DynamicJaxrsTest brxm) {
    String response = brxm.request()
        .get("/site/api/admin/users")
        .asUser("admin", "admin", "editor")  // username, roles...
        .execute();

    assertThat(response).contains("users");
}

// Role-only (no username needed)
@Test
void testRoleBasedAccess(DynamicJaxrsTest brxm) {
    String response = brxm.request()
        .get("/site/api/reports")
        .withRole("manager", "viewer")       // roles only
        .execute();

    assertThat(response).contains("reports");
}
          

PageModel API


@Test
void testPageModelApi(DynamicPageModelTest brxm) throws Exception {
    PageModelResponse pageModel = brxm.request()
        .get("/site/resourceapi/")
        .executeAsPageModel();  // Parse response as PageModelResponse

    // Navigate component tree
    PageComponent root = pageModel.getRootComponent();
    assertNotNull(root);

    // Find component by name
    PageComponent header = pageModel.findComponentByName("header").orElseThrow();

    // Get children
    List<PageComponent> children = pageModel.getChildComponents(root);
}
          

Repository Access


@Test
void testRepositoryAccess(DynamicJaxrsTest brxm) {
    try (RepositorySession session = brxm.repository()) {
        session.assertNodeExists("/hst:myproject")
               .assertNodeExists("/hippo:configuration");

        Node newsNode = session.getNode("/content/documents/news");
        assertEquals("hippo:handle", newsNode.getPrimaryNodeType().getName());
    }
    // Auto-cleanup on try-with-resources exit
}
          

5. Component Test Patterns

Annotation-Driven Setup


@BrxmComponentTest(
    beanPackages = {"org.example.beans"},
    content = "/test-content.yaml",
    contentRoot = "/content/documents/myproject"
)
class MyComponentTest {

    @Test
    void testComponent(DynamicComponentTest brxm) {
        // Node types auto-detected from @Node annotations!
        // Content imported automatically from annotation parameters
        MyComponent component = new MyComponent();
        component.init(null, brxm.getComponentConfiguration());
        component.doBeforeRender(brxm.getHstRequest(), brxm.getHstResponse());

        MyModel model = brxm.getRequestAttributeValue("model");
        assertNotNull(model);
    }
}
          

Mocking Component Parameters


@Test
void testComponentWithParameters(DynamicComponentTest brxm) {
    // Mock the ParameterInfo interface
    MyComponentInfo paramInfo = mock(MyComponentInfo.class);
    when(paramInfo.getDocument()).thenReturn("articles/my-article");
    when(paramInfo.getPageSize()).thenReturn(10);

    // Set on request
    brxm.setComponentParameters(paramInfo);

    // Execute component
    component.doBeforeRender(brxm.getHstRequest(), brxm.getHstResponse());

    // Assert on model attributes
    MyModel model = brxm.getRequestAttributeValue("model");
    assertThat(model).isNotNull();
}
          

Request Parameters


@Test
void testWithRequestParameters(DynamicComponentTest brxm) {
    // Add request parameters
    brxm.addRequestParameter("page", "2");
    brxm.addRequestParameter("sort", "date");

    component.doBeforeRender(brxm.getHstRequest(), brxm.getHstResponse());
}
          

6. HTTP Session Support


@Test
void testWithSession(DynamicComponentTest brxm) {
    // Get or create session (lazy initialization)
    HttpSession session = brxm.getHstRequest().getSession();
    session.setAttribute("user", new User("John"));

    component.doBeforeRender(brxm.getHstRequest(), brxm.getHstResponse());

    // Verify session was used
    assertThat(session.getAttribute("loginCount")).isEqualTo(1);
}

// Mock session for more control
@Test
void testWithMockedSession(DynamicComponentTest brxm) {
    HttpSession session = mock(HttpSession.class);
    when(session.getAttribute("user")).thenReturn(new User("Jane"));

    brxm.getHstRequest().setSession(session);

    component.doBeforeRender(brxm.getHstRequest(), brxm.getHstResponse());
}
          

Session Isolation: Sessions are automatically invalidated between tests for JAX-RS/PageModel tests.

7. Production Config (ConfigService)

One-Liner


@BrxmJaxrsTest(
    beanPackages = {"org.example.model"},
    loadProjectContent = true  // Uses HCM modules from classpath
)
          

HCM Structure


src/test/resources/
├── META-INF/
│   └── hcm-module.yaml
├── hcm-config/
│   └── hst/
│       ├── configurations.yaml
│       ├── hosts.yaml
│       └── sites.yaml
└── hcm-content/
    └── content/
        └── documents/
          

See ConfigService Repository Guide for detailed setup.

Annotation Parameter Reference

@BrxmJaxrsTest

Parameter Type Default Description
beanPackages String[] auto-detected HST content bean packages (from project-settings.xml or classpath scan)
resources Class<?>[] {} JAX-RS resource classes (recommended - eliminates Spring XML)
hstRoot String auto-detected HST configuration root (from Maven artifactId)
springConfigs String[] auto-detected Spring XML configs (only for Spring-managed dependencies)
yamlPatterns String[] auto-detected YAML patterns (from <testPackage>/imports/**/*.yaml)
cndPatterns String[] {} CND node type definition patterns
loadProjectContent boolean true Load real HCM modules via ConfigServiceRepository

@BrxmPageModelTest

Parameter Type Default Description
beanPackages String[] auto-detected HST content bean packages
hstRoot String auto-detected HST configuration root
springConfig String auto-detected Spring XML config for PageModel pipeline
loadProjectContent boolean false Load real HCM modules via ConfigServiceRepository

@BrxmComponentTest

Parameter Type Default Description
beanPackages String[] auto-detected HST content bean packages
nodeTypes String[] auto-detected Node types (from @Node annotations in beanPackages)
content String "" Classpath path to YAML file with test content
contentRoot String "" JCR path where content is imported + sets site base

Auto-Detection Rules

Setting Auto-Detection Strategy Override
Bean Packages 1. project-settings.xml
2. @Node classpath scan
3. pom.xml groupId
4. test class package
beanPackages = {"org.example.beans"}
HST Root /hst:${artifactId} from pom.xml hstRoot = "/hst:customname"
Spring Configs JAX-RS: custom-jaxrs.xml, rest-resources.xml
PageModel: custom-pagemodel.xml
springConfigs = {"/path/to/config.xml"}
Node Types Scans @Node(jcrType="...") in beanPackages nodeTypes = {"ns:Type extends ns:Base"}
Test YAML <testPackage>/imports/**/*.yaml yamlPatterns = {"classpath*:custom/**/*.yaml"}

Troubleshooting

Issue Fix
NullPointerException on brxm Use parameter injection: void test(DynamicJaxrsTest brxm)
"Missing @BrxmJaxrsTest annotation" Add annotation to test class
"Bean packages: NONE" warning Verify project-settings.xml exists, or add explicit beanPackages
Spring config not found Verify file exists, use absolute path starting with /
HST root not found Override with hstRoot = "/hst:actualname"
IDE "field never assigned" warning Use parameter injection (recommended) or add @SuppressWarnings("unused")