Files
everything-claude-code/rules/fsharp/testing.md
2026-05-11 21:43:17 -04:00

63 lines
1.7 KiB
Markdown

---
paths:
- "**/*.fs"
- "**/*.fsx"
- "**/*.fsproj"
---
# F# Testing
> This file extends [common/testing.md](../common/testing.md) with F#-specific content.
## Test Framework
- Prefer **xUnit** with **FsUnit.xUnit** for F#-friendly assertions
- Use **Unquote** for quotation-based assertions with clear failure messages
- Use **FsCheck.xUnit** for property-based testing
- Use **NSubstitute** or function stubs for mocking dependencies
- Use **Testcontainers** when integration tests need real infrastructure
## Test Organization
- Mirror `src/` structure under `tests/`
- Separate unit, integration, and end-to-end coverage clearly
- Name tests by behavior, not implementation details
```fsharp
open Xunit
open Swensen.Unquote
[<Fact>]
let ``PlaceOrder returns success when request is valid`` () =
let request = { CustomerId = "cust-123"; Items = [ validItem ] }
let result = OrderService.placeOrder request
test <@ Result.isOk result @>
[<Fact>]
let ``PlaceOrder returns error when items are empty`` () =
let request = { CustomerId = "cust-123"; Items = [] }
let result = OrderService.placeOrder request
test <@ Result.isError result @>
```
## Property-Based Testing with FsCheck
```fsharp
open FsCheck.Xunit
[<Property>]
let ``order total is never negative`` (items: OrderItem list) =
let total = Order.calculateTotal items
total >= 0m
```
## ASP.NET Core Integration Tests
- Use `WebApplicationFactory<TEntryPoint>` for API integration coverage
- Test auth, validation, and serialization through HTTP, not by bypassing middleware
## Coverage
- Target 80%+ line coverage
- Focus coverage on domain logic, validation, auth, and failure paths
- Run `dotnet test` in CI with coverage collection enabled where available