# Write Unit Tests for an ASP.NET Core Project

Yes. An agent runs coverage on an ASP.NET Core API, adds xUnit tests for the thinnest logic files, and opens a pull request with the delta.

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

## What the agent does

The agent reads the .NET layout before it writes tests. In realworld-apps/aspnetcore-realworld-example-app it finds `global.json` pinning SDK `10.0.402` with `rollForward: latestFeature`, the web project at `src/Conduit/Conduit.csproj` (EF Core Sqlite/SqlServer, JWT Bearer, FluentValidation, Mediator source generator, Mapperly, Swashbuckle), and tests at `tests/Conduit.IntegrationTests/` with xUnit `2.9.3`, `Microsoft.AspNetCore.Mvc.Testing` and `Microsoft.NET.Test.Sdk`. Feature slices live under `src/Conduit/Features/` (`Articles`, `Comments`, `Users`, `Profiles`, `Tags`, `Favorites`, `Followers`) as Mediator handlers such as `Articles/Create.cs` and `Users/Login.cs`.

Existing coverage is integration-heavy: `CreateTests`, `EditTests`, `DeleteTests`, `LoginTests`, `PasswordHashingTests` and friends go through `SliceFixture` and `ApiFactory` rather than pure unit tests beside each handler. The agent runs the suite with coverage (`dotnet test` with a coverlet or DataCollector argument the project already accepts, or adds the smallest coverlet package reference on the test project when none exists) and ranks `src/Conduit` files by line coverage, focusing on handlers and helpers that hold branching logic (`ArticleExtensions`, `ProfileReader`, follower and favorite commands) rather than controller shells or envelope DTOs.

For the five weakest logic files it adds xUnit tests that exercise behaviour: duplicate tag collapsing in `Create.Handler`, authorization failures on edit/delete for the wrong user, profile mapping when the current user is null, validator failures from FluentValidation rules. New tests may live under a new `tests/Conduit.UnitTests/` project mirroring the feature folders, or beside integration tests when that matches the repo; they construct handlers with in-memory `DbContext` and `StubCurrentUserAccessor` the way `CreateTests` already does, instead of asserting on private fields.

It re-runs `dotnet test` with coverage, puts before/after percentages in the pull request description, and changes production code only when a test exposes a real bug (called out explicitly). SDK version stays on the `global.json` pin. Build scripts such as `build.sh` / `Makefile` targets are left alone unless the only documented way to run tests with coverage is through them, in which case the pull request quotes that command.

## 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 xUnit 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 Conduit-shaped repo it adds xUnit test classes (and a unit test project if one was missing), keeps `src/Conduit` unchanged absent a documented bugfix, and may add a coverlet package reference on the test project so coverage can be collected in CI the same way.

The description reports coverage before and after, names the five files chosen, and links each to the new tests. The trajectory keeps `dotnet test` output and the coverage summary.

Before merging, a reviewer checks that tests hit behaviour (status codes, persisted tags, auth failures) rather than Mediator internals, that the SDK matches `global.json`, and that any production diff is a real bugfix. Once merged, `dotnet test` in CI runs the new cases.

## Run it on every coverage drop on main

Schedule a weekly run or trigger from your coverage reporter when `src/Conduit` coverage falls past a threshold. Your server sends this request with the repository in `resources` so the agent opens a pull request that restores the thin files.

Use the API key webhook for completion events and stay within `max_concurrent` when sweeping several .NET services.

## Why run it on Rush?

Collecting .NET coverage and iterating on handler tests needs the SDK pin, restore, and a quiet machine. On Rush the agent restores against `global.json`, runs `dotnet test` with coverage in its sandbox, and only surfaces a pull request when the new tests pass and the delta is written down.

The proof is the coverage summary and the xUnit output in the trajectory, not a claim that "tests were added". Several APIs can be hardened in parallel, each with a reviewable pull request.

## Frequently asked questions

### Unit tests or more integration tests?

The job targets unit-level behaviour around handlers and helpers. It reuses in-memory EF and stubs from `SliceFixture` when that is the project's pattern, but it does not replace the existing `Conduit.IntegrationTests` suite.

### Which .NET SDK does it use?

The one in `global.json` (currently `10.0.402` with `rollForward: latestFeature`). It does not invent a different major.

### Will it modify Mediator handlers to make them testable?

Only if a test exposes a bug, and then the pull request says so. Otherwise production code stays put; handlers are already constructable with a `DbContext` and `ICurrentUserAccessor`.

### xUnit, NUnit or MSTest?

Whatever the test project already references. This RealWorld port uses xUnit, so new tests use `[Fact]` and `Assert` from xUnit.
