# Write Unit Tests for a Spring Boot Project

Yes. An agent runs JUnit 5 coverage on a Spring Boot API, adds tests for the thinnest logic, and opens a pull request with the delta.

[Run this on Rush](https://cloud.getrush.ai/run/write-unit-tests/spring-boot/), in a Project that has your repository.

## What the agent does

The agent reads the Gradle build and package layout first. In gothinkster/spring-boot-realworld-example-app it finds `build.gradle` on Spring Boot `2.6.3`, Java `11`, MyBatis, Netflix DGS GraphQL `4.9.21`, Flyway, JJWT, SQLite, Spotless with Google Java Format, and `tasks.named('test') { useJUnitPlatform() }`. Production code under `src/main/java/io/spring` splits into `api` (MVC controllers, JWT filter, security config), `core` (entities and `AuthorizationService`), `application` (query services), `infrastructure` (MyBatis repositories and JWT service), and `graphql` (data fetchers and mutations). Tests under `src/test/java` already cover many API and MyBatis paths (`ArticlesApiTest`, `UsersApiTest`, `MyBatisUserRepositoryTest`, `ArticleTest` for slug behaviour) but leave gaps in places such as `AuthorizationService`, `Util`, GraphQL fetchers (`ArticleDatafetcher`, `CommentMutation`, `SecurityUtil`), and some infrastructure helpers.

It runs `./gradlew test` with JaCoCo (adding the JaCoCo plugin to `build.gradle` only when the project has no coverage task yet) and ranks main sources by missed lines. The five files it picks must hold branches: for example `AuthorizationService.canWriteArticle` / `canWriteComment`, GraphQL security helpers, exception handlers under `api/exception`, or query services without a matching `*Test.java`. Envelope DTOs and generated DGS classes are skipped.

New tests are JUnit 5 (`org.junit.jupiter.api.Test`) in the matching package under `src/test/java`, following styles already in the repo: Hamcrest assertions like `ArticleTest`, Spring `@SpringBootTest` / MockMvc / RestAssured where neighbouring API tests use them, and plain unit tests for pure core services with constructed `User`, `Article` and `Comment` instances. Behaviour is the focus: authorization true/false matrix, slug edge cases not already listed, GraphQL error paths when the current user is missing.

It re-runs the Gradle test task with coverage, puts before/after figures in the pull request description, and leaves production Java unchanged unless a test finds a bug (documented in the description). Spotless formatting is applied so the PR does not fail the format check. The clean task's deletion of `./dev.db` is respected so leftover SQLite files from one attempt do not poison the next.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Run the test suite with coverage, pick the five least-covered files that hold real logic, and write JUnit 5 tests for them that exercise behaviour, not implementation details. Do not change production code unless a test reveals a bug; if it does, say so in the description. Open a pull request with the coverage before and after.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request on a new branch. In a RealWorld Spring Boot repo it adds JUnit 5 classes under `src/test/java/io/spring/...`, may add a JaCoCo block to `build.gradle` when coverage was missing, and keeps `src/main/java` clean absent a named bug fix.

The description lists the five files, coverage before and after, and the Gradle commands used. The trajectory keeps `./gradlew test` output and any SQLite `dev.db` cleanup from the clean task, so a reviewer can see flaky file locking if it happened.

Before merging, a reviewer checks Java 11 compatibility, that GraphQL tests do not require an external network, and that Spotless still passes. Once merged, the Java CI workflow runs the new tests with the same JUnit Platform settings already in `build.gradle`.

## Run it on every domain service or GraphQL fetcher added

On pull requests that add files under `io.spring.core` or `io.spring.graphql` without a matching test, send this request so JUnit coverage arrives before merge.

Wire the API key webhook for `run.completed` / `run.failed` and keep Gradle runs inside `max_concurrent` so the sandbox is not flooded with JVM builds.

## Why run it on Rush?

Spring Boot tests need the right JDK, Gradle wrapper, and often an in-memory or SQLite database. Running that loop on a laptop while juggling other services is slow. On Rush the agent uses the project's `gradlew`, writes JUnit 5 tests in the repo's style, and opens a pull request that already passes.

Coverage numbers on the pull request and the Gradle log in the trajectory are the proof. The same request can raise coverage on several Spring services in parallel, each reviewed separately.

## Frequently asked questions

### JUnit 4 or JUnit 5?

JUnit 5. The build already calls `useJUnitPlatform()` and existing tests import `org.junit.jupiter.api.Test`.

### Will it upgrade Spring Boot 2.6?

No. This job only adds tests (and JaCoCo if needed). Framework upgrades are a different request.

### Are GraphQL tests included?

Yes when coverage points at `io.spring.graphql`. The agent follows DGS testing patterns already possible with `spring-boot-starter-test` rather than adding a second framework.

### MyBatis tests against which database?

Whatever the test resources already use (SQLite in this RealWorld app). The agent does not point tests at a shared staging database, and it does not commit a leftover `dev.db` from the sandbox into the pull request.
