Multi-Spec OpenAPI Support ========================== BerryCrush supports working with multiple OpenAPI specifications in a single test suite. This is useful when your API is split across multiple spec files or when you need to test different API versions. Configuring Multiple Specs -------------------------- Using @BerryCrushSpec Annotation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The simplest way to configure specs is using the ``@BerryCrushSpec`` annotation: .. code-block:: kotlin @BerryCrushSpec(paths = ["petstore.yaml"]) @BerryCrushConfiguration(bindings = MyBindings::class) class MyTest For multiple specs, use repeatable annotations: .. code-block:: kotlin @BerryCrushSpec(paths = ["petstore.yaml"], name = "default") @BerryCrushSpec(paths = ["auth.yaml"], name = "auth") @BerryCrushConfiguration(bindings = MyBindings::class) class MyTest Using getBindings() Method ^^^^^^^^^^^^^^^^^^^^^^^^^^ For dynamic configuration (e.g., runtime ports), use ``OpenApiSpecValue`` in ``getBindings()``: .. code-block:: java @Component @Lazy public class PetstoreBindings implements BerryCrushBindings { @LocalServerPort private int port; @Override public Map getBindings() { String host = "http://localhost:" + port; return Map.of( "default", new OpenApiSpecValue("petstore.yaml", host + "/api/v1"), "auth", new OpenApiSpecValue("auth.yaml", host + "/auth/api/v1") ); } } Using Named Specs in Scenarios ------------------------------ Default Operations ^^^^^^^^^^^^^^^^^^ Operations from the default spec can be called directly: .. code-block:: berrycrush scenario: List all pets when I request pets call ^listPets then I get a response assert status 200 Named Spec Operations ^^^^^^^^^^^^^^^^^^^^^ To call operations from a named spec, use the ``using`` keyword: .. code-block:: berrycrush scenario: Authenticate and list pets given I have valid credentials call using auth ^login body: {"username": "test", "password": "test"} then authentication returns a token assert status 200 extract $.token => authToken when I request pets call ^listPets then I get a response assert status 200 The syntax is: ``call using ^`` Example: Separating Auth from Main API -------------------------------------- **auth.yaml:** .. code-block:: yaml openapi: 3.0.3 info: title: Authentication API version: 1.0.0 paths: /auth/login: post: operationId: login requestBody: required: true content: application/json: schema: type: object properties: username: type: string password: type: string responses: '200': description: Login successful content: application/json: schema: type: object properties: token: type: string /auth/logout: post: operationId: logout responses: '200': description: Logout successful **petstore.yaml:** .. code-block:: yaml openapi: 3.0.3 info: title: Pet Store API version: 1.0.0 paths: /pets: get: operationId: listPets responses: '200': description: List of pets **auth.scenario:** .. code-block:: berrycrush # Authentication tests using the 'auth' spec scenario: Successful Login given I have valid credentials call using auth ^login body: {"username": "test", "password": "test"} then authentication returns a token assert status 200 extract $.token => authToken scenario: Logout when I log out call using auth ^logout then logout is successful assert status 200 Auto-Resolution --------------- When an ``operationId`` is unique across all registered specs, BerryCrush can automatically resolve which spec to use without the ``using`` keyword. .. warning:: If the same ``operationId`` exists in multiple specs, you must use ``using`` to disambiguate. BerryCrush will throw an ``AmbiguousOperationException`` if it cannot determine which spec to use. Multi-Host API Testing ---------------------- In microservices environments, different APIs often run on different hosts or ports. BerryCrush supports this through per-spec base URL configuration via ``getBindings()``. Configuring Per-Spec Base URLs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use ``OpenApiSpecValue`` in ``getBindings()`` to provide different base URLs for each spec: .. code-block:: java @Component @Lazy public class MicroservicesBindings implements BerryCrushBindings { @Value("${petstore.host:http://localhost:8080}") private String petstoreHost; @Value("${auth.host:http://localhost:8081}") private String authHost; @Value("${inventory.host:http://localhost:8082}") private String inventoryHost; @Override public Map getBindings() { return Map.of( "default", new OpenApiSpecValue("petstore.yaml", petstoreHost), "auth", new OpenApiSpecValue("auth.yaml", authHost), "inventory", new OpenApiSpecValue("inventory.yaml", inventoryHost) ); } } Cross-Service Scenarios ^^^^^^^^^^^^^^^^^^^^^^^ With multi-host configuration, you can test scenarios that span multiple services: .. code-block:: berrycrush scenario: Cross-service order flow given I am authenticated call using auth ^login body: {"username": "test", "password": "test"} then I get a token assert status 200 extract $.token => authToken when I check inventory call using inventory ^checkStock header_Authorization: "Bearer {{authToken}}" productId: 123 then product is available assert status 200 assert $.available equals true when I create an order call ^createOrder header_Authorization: "Bearer {{authToken}}" body: {"productId": 123, "quantity": 1} then order is created assert status 201 extract $.orderId => orderId File-Level Base URL Overrides ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can also override per-spec base URLs using file-level parameters for testing against different environments: .. code-block:: berrycrush parameters: baseUrl.auth: "http://staging-auth.example.com" baseUrl.default: "http://staging-api.example.com" scenario: Test against staging given I authenticate call using auth ^login body: {"username": "staging-user", "password": "secret"} then I get access assert status 200 Best Practices -------------- 1. **Organize by domain**: Split specs by functional area (auth, admin, public API) 2. **Use unique operationIds**: Avoid duplicate operationIds across specs 3. **Document spec dependencies**: Note which tests require which specs 4. **Keep default spec focused**: Use the default for your main API operations 5. **Use environment variables**: Configure hosts via environment variables for flexibility