
Fsharp Testing
- 1.4k installs
- 238k repo stars
- Updated August 5, 2026
- affaan-m/ecc
This is a copy of fsharp-testing by affaan-m - installs and ranking accrue to the original listing.
fsharp-testing is an ECC agent skill that generates and reviews unit, property-based, and integration tests for F# applications using xUnit, FsUnit, Unquote, and FsCheck for developers who want idiomatic functional testi
About
fsharp-testing is an ECC skill documenting comprehensive testing patterns for F# applications on the standard .NET test stack. It maps four core tools—xUnit as the test framework, FsUnit.xUnit for F#-friendly assertions, Unquote for quotation-based failure messages, and FsCheck.xUnit for property-based tests—plus modern .NET practices for integration coverage. Developers activate fsharp-testing when writing new F# tests, reviewing test quality, setting up test infrastructure, or debugging flaky and slow suites. The skill emphasizes functional approaches such as property tests alongside example-based unit and integration tests. Reach for fsharp-testing whenever F# services need reliable automated coverage rather than ad hoc C#-style assertion patterns.
- Full F# testing stack: xUnit + FsUnit + Unquote + FsCheck + NSubstitute + Testcontainers
- Property-based testing patterns with FsCheck.xUnit
- Clear F#-friendly assertion syntax and readable failure messages
- Integration test recipes using WebApplicationFactory and real containers
- Test organization and naming conventions that scale with growing codebases
Fsharp Testing by the numbers
- 1,357 all-time installs (skills.sh)
- +83 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/affaan-m/ecc --skill fsharp-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 238k |
| Last updated | August 5, 2026 |
| Repository | affaan-m/ecc ↗ |
How do you write property-based tests in F#?
Generate high-quality unit, property-based, and integration tests for F# services using xUnit, FsUnit, Unquote, and FsCheck.
Who is it for?
.NET developers writing or reviewing F# services who want idiomatic xUnit, FsUnit, Unquote, and FsCheck test patterns.
Skip if: C#-only codebases or teams seeking UI end-to-end browser tests without F# unit or property-based coverage needs.
When should I use this skill?
A developer writes F# tests, reviews F# test quality, sets up F# test infrastructure, or debugs flaky F# test suites.
What you get
xUnit test suites, FsCheck property tests, FsUnit assertion blocks, Unquote quotation failures, and F# integration test scaffolding.
- F# unit test files
- FsCheck property tests
- Integration test scaffolding
By the numbers
- Documents a 4-tool F# test stack: xUnit, FsUnit.xUnit, Unquote, and FsCheck.xUnit
Files
F# Testing Patterns
Comprehensive testing patterns for F# applications using xUnit, FsUnit, Unquote, FsCheck, and modern .NET testing practices.
When to Activate
- Writing new tests for F# code
- Reviewing test quality and coverage
- Setting up test infrastructure for F# projects
- Debugging flaky or slow tests
Test Framework Stack
| Tool | Purpose |
|---|---|
| xUnit | Test framework (standard .NET ecosystem choice) |
| FsUnit.xUnit | F#-friendly assertion syntax for xUnit |
| Unquote | Assertion library using F# quotations for clear failure messages |
| FsCheck.xUnit | Property-based testing integrated with xUnit |
| NSubstitute | Mocking .NET dependencies |
| Testcontainers | Real infrastructure in integration tests |
| WebApplicationFactory | ASP.NET Core integration tests |
Unit Tests with xUnit + FsUnit
Basic Test Structure
module OrderServiceTests
open Xunit
open FsUnit.Xunit
[<Fact>]
let ``create sets status to Pending`` () =
let order = Order.create "cust-1" [ validItem ]
order.Status |> should equal Pending
[<Fact>]
let ``confirm changes status to Confirmed`` () =
let order = Order.create "cust-1" [ validItem ]
let confirmed = Order.confirm order
confirmed.Status |> should be (ofCase <@ Confirmed @>)Assertions with Unquote
Unquote uses F# quotations so failure messages show the full expression that failed, not just "expected X got Y".
module OrderValidationTests
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 ``order total sums item prices`` () =
let items = [ { Sku = "A"; Quantity = 2; Price = 10m }
{ Sku = "B"; Quantity = 1; Price = 5m } ]
let total = Order.calculateTotal items
test <@ total = 25m @>
[<Fact>]
let ``validated email rejects empty input`` () =
let result = ValidatedEmail.create ""
test <@ Result.isError result @>Async Tests
[<Fact>]
let ``PlaceOrder returns success when request is valid`` () = task {
let deps = createTestDeps ()
let request = { CustomerId = "cust-123"; Items = [ validItem ] }
let! result = OrderService.placeOrder deps request
test <@ Result.isOk result @>
}
[<Fact>]
let ``PlaceOrder returns error when items are empty`` () = task {
let deps = createTestDeps ()
let request = { CustomerId = "cust-123"; Items = [] }
let! result = OrderService.placeOrder deps request
test <@ Result.isError result @>
}Parameterized Tests with Theory
[<Theory>]
[<InlineData("")>]
[<InlineData(" ")>]
let ``PlaceOrder rejects empty customer ID`` (customerId: string) =
let request = { CustomerId = customerId; Items = [ validItem ] }
let result = OrderService.placeOrder request
result |> should be (ofCase <@ Error @>)
[<Theory>]
[<InlineData("", false)>]
[<InlineData("a", false)>]
[<InlineData("user@example.com", true)>]
[<InlineData("user+tag@example.co.uk", true)>]
let ``IsValidEmail returns expected result`` (email: string, expected: bool) =
test <@ EmailValidator.isValid email = expected @>Property-Based Testing with FsCheck
Using FsCheck.xUnit
open FsCheck
open FsCheck.Xunit
[<Property>]
let ``order total is always non-negative`` (items: NonEmptyList<PositiveInt * decimal>) =
let orderItems =
items.Get
|> List.map (fun (qty, price) ->
{ Sku = "SKU"; Quantity = qty.Get; Price = abs price })
let total = Order.calculateTotal orderItems
total >= 0m
[<Property>]
let ``serialization roundtrips`` (order: Order) =
let json = JsonSerializer.Serialize order
let deserialized = JsonSerializer.Deserialize<Order> json
deserialized = orderCustom Generators
type OrderGenerators =
static member ValidEmail () =
gen {
let! user = Gen.elements [ "alice"; "bob"; "carol" ]
let! domain = Gen.elements [ "example.com"; "test.org" ]
return $"{user}@{domain}"
}
|> Arb.fromGen
[<Property(Arbitrary = [| typeof<OrderGenerators> |])>]
let ``valid emails pass validation`` (email: string) =
EmailValidator.isValid emailMocking Dependencies
Function Stubs (Preferred)
let createTestDeps () =
let mutable savedOrders = []
{ FindOrder = fun id -> task { return Map.tryFind id testData }
SaveOrder = fun order -> task { savedOrders <- order :: savedOrders }
SendNotification = fun _ -> Task.CompletedTask }
[<Fact>]
let ``PlaceOrder saves the confirmed order`` () = task {
let mutable saved = []
let deps =
{ createTestDeps () with
SaveOrder = fun order -> task { saved <- order :: saved } }
let! _ = OrderService.placeOrder deps validRequest
test <@ saved.Length = 1 @>
}NSubstitute for .NET Interfaces
open NSubstitute
[<Fact>]
let ``calls repository with correct ID`` () = task {
let repo = Substitute.For<IOrderRepository>()
repo.FindByIdAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>())
.Returns(Task.FromResult(Some testOrder))
let service = OrderService(repo)
let! _ = service.GetOrder(testOrder.Id, CancellationToken.None)
do! repo.Received(1).FindByIdAsync(testOrder.Id, Arg.Any<CancellationToken>())
}ASP.NET Core Integration Tests
type OrderApiTests (factory: WebApplicationFactory<Program>) =
interface IClassFixture<WebApplicationFactory<Program>>
let client =
factory.WithWebHostBuilder(fun builder ->
builder.ConfigureServices(fun services ->
services.RemoveAll<DbContextOptions<AppDbContext>>() |> ignore
services.AddDbContext<AppDbContext>(fun options ->
options.UseInMemoryDatabase("TestDb") |> ignore) |> ignore))
.CreateClient()
[<Fact>]
member _.``GET order returns 404 when not found`` () = task {
let! response = client.GetAsync($"/api/orders/{Guid.NewGuid()}")
test <@ response.StatusCode = HttpStatusCode.NotFound @>
}Test Organization
tests/
MyApp.Tests/
Unit/
OrderServiceTests.fs
PaymentServiceTests.fs
Integration/
OrderApiTests.fs
OrderRepositoryTests.fs
Properties/
OrderPropertyTests.fs
Helpers/
TestData.fs
TestDeps.fsCommon Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
| Testing implementation details | Test behavior and outcomes |
| Mutable shared test state | Fresh state per test |
Thread.Sleep in async tests | Use Task.Delay with timeout, or polling helpers |
Asserting on sprintf output | Assert on typed values and pattern matches |
Ignoring CancellationToken | Always pass and verify cancellation |
| Skipping property-based tests | Use FsCheck for any function with clear invariants |
Related Skills
dotnet-patterns- Idiomatic .NET patterns, dependency injection, and architecturecsharp-testing- C# testing patterns (shared infrastructure like WebApplicationFactory and Testcontainers applies to F# too)
Running Tests
# Run all tests
dotnet test
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific project
dotnet test tests/MyApp.Tests/
# Filter by test name
dotnet test --filter "FullyQualifiedName~OrderService"
# Watch mode during development
dotnet watch test --project tests/MyApp.Tests/Related skills
How it compares
Use fsharp-testing for idiomatic F# assertions and FsCheck properties; use general .NET testing skills when the codebase is C#-only.
FAQ
Which test libraries does fsharp-testing cover?
fsharp-testing covers xUnit, FsUnit.xUnit, Unquote, and FsCheck.xUnit for F# applications. It documents unit, property-based, and integration patterns plus infrastructure setup and flaky-test debugging on modern .NET.
Does fsharp-testing support property-based testing?
fsharp-testing includes FsCheck.xUnit patterns for property-based tests alongside example-based unit and integration tests, helping F# developers validate invariants with generated inputs instead of hand-picked cases alone.