Tutorial

This tutorial walks you through building a complete API test suite using BerryCrush.

Overview

We’ll create tests for a simple Pet Store API that supports:

  • Listing all pets

  • Creating a new pet

  • Getting a pet by ID

  • Updating a pet

  • Deleting a pet

By the end, you’ll understand how to:

  • Write BDD-style scenarios

  • Use data tables and examples

  • Create custom step definitions

  • Configure plugins for reporting

  • Integrate with Spring Boot

Project Setup

  1. Create a new Gradle project with Kotlin DSL:

mkdir petstore-tests
cd petstore-tests
gradle init --type kotlin-application
  1. Update build.gradle.kts:

plugins {
    kotlin("jvm") version "2.0.0"
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.berrycrush.berrycrush:core:0.1.0")
    testImplementation("org.berrycrush.berrycrush:junit:0.1.0")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}

tasks.test {
    useJUnitPlatform()
}

Writing Scenarios

Basic Scenario

Create src/test/resources/scenarios/pets.scenario:

scenario: List all pets
  when: I request all pets
    call ^listPets
  then: I receive a list
    assert status 200
    assert $.pets notEmpty

scenario: Create a new pet
  when: I create a pet
    call ^createPet
      body:
        name: "Fluffy"
        category: "cat"
  then: pet is created
    assert status 201
    assert $.name equals "Fluffy"
    assert $.category equals "cat"
    extract $.id => petId

Scenario Outline with Examples

Use outline: and examples: for parameterized tests:

outline: Create pets of different categories
  when: I create a pet named {{name}} in category {{category}}
    call ^createPet
      body:
        name: "{{name}}"
        category: "{{category}}"
  then: pet is created
    assert status 201
    assert $.name equals "{{name}}"

  examples:
    | name   | category |
    | Fluffy | cat      |
    | Buddy  | dog      |
    | Tweety | bird     |

Advanced Scenarios

scenario: Get pet by ID
  given: a pet exists
    call ^createPet
      body:
        name: "Max"
    assert status 201
    extract $.id => petId
  when: I request the pet
    call ^getPetById
      petId: {{petId}}
  then: I receive the pet
    assert status 200
    assert $.name equals "Max"

scenario: Update a pet
  given: a pet exists
    call ^createPet
      body:
        name: "Max"
    assert status 201
    extract $.id => petId
  when: I update the pet
    call ^updatePet
      petId: {{petId}}
      body:
        name: "Maximum"
  then: pet is updated
    assert status 200
    assert $.name equals "Maximum"

Conditional Assertions

When APIs can return different valid responses, use if/else:

scenario: Upsert a pet
  when: I upsert pet 999
    call ^updatePet
      petId: 999
      body:
        name: "NewPet"

    if status 201
      # Pet was created
      assert $.id equals 999
    else if status 200
      # Pet was updated
      assert $.name equals "NewPet"
    else
      fail "Expected 200 or 201"

Auto-Generated Tests

BerryCrush can automatically generate invalid request and security tests based on your OpenAPI schema. This helps ensure your API properly validates input and rejects common attack patterns.

Basic Usage

Use the auto: directive in a call to generate tests:

scenario: Auto-generated tests for createPet
  when: I create a pet with invalid data
    call ^createPet
      auto: [invalid security]
      body:
        name: "TestPet"
        status: "available"

  if status 4xx
    # Test passed - invalid request rejected
  else
    fail "Expected 4xx for {{test.type}}: {{test.description}}"

Test Types

  • invalid - Generates tests that violate OpenAPI constraints:

    • String length violations (minLength, maxLength)

    • Number range violations (minimum, maximum)

    • Pattern violations

    • Missing required fields

    • Invalid enum values

    • Type mismatches

  • security - Generates tests with common attack payloads:

    • SQL injection

    • Cross-site scripting (XSS)

    • Path traversal

    • Command injection

    • LDAP injection

Context Variables

During auto-test execution, these variables are available:

Path Parameter Tests

Auto-tests also work with path parameters:

scenario: Auto-generated tests for getPetById
  when: I get a pet with invalid ID
    call ^getPetById
      auto: [invalid security]
      petId: 1

  if status 4xx
    # Invalid ID rejected

See Auto-Generated Tests for complete documentation.

Running Tests

Run all tests:

./gradlew test

Run a specific scenario:

./gradlew test --tests "*PetApiTest*"

Generating Reports

Configure the JSON report plugin:

@BerryCrushConfiguration(
    plugins = ["report:json:build/reports/berrycrush.json"]
)

See Reporting for more report formats.

Spring Boot Integration

For Spring Boot projects, add the Spring module:

testImplementation("org.berrycrush.berrycrush:spring:0.1.0")

Then use Spring’s test annotations:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@IncludeEngines("berrycrush")
@BerryCrushScenarios(locations = "scenarios/pets.scenario")
class PetApiTest {
    @LocalServerPort
    var port: Int = 0
}

The Spring integration will automatically discover bindings from the Spring context.

Conclusion

You’ve learned how to:

  • Set up a BerryCrush project

  • Write BDD-style scenarios

  • Use scenario outlines with examples

  • Create custom step definitions

  • Generate auto-tests for input validation and security

  • Generate reports

  • Integrate with Spring Boot

For more details, explore: