Property-based Testing in C#: Catch Bugs That Unit Tests Miss

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Your Unit Test Is Lying (And You Know It)

\n\n

Imagine: you wrote 50 unit tests, all green, 90% coverage. You're satisfied. But a week later, production crashes. It turns out your SortArray() method works perfectly for [1, 2, 3] and [3, 1, 2], but fails on [int.MaxValue, -1, 0]. Sound familiar?

\n\n

The problem with classic unit tests is developer bias. You write tests for the data you expect. Hackers, real users, and random edge cases play by different rules.

\n\n

This is where property-based testing in C# comes into play. Instead of checking "if A, then B", you describe properties that should always be true. The framework itself generates hundreds of random inputs and checks your assertions.

\n\n

In this article, we'll break down how to implement property-based testing in C# using the FsCheck library, write real examples, and see how it catches bugs that regular tests miss.

\n\n

What is Property-Based Testing?

\n\n

Property-based testing is an approach where you formulate invariants (properties) of your program. For example:

\n
    \n
  • "After sorting, the length of the array does not change"
  • \n
  • "Reversing a string twice gives the original string"
  • \n
  • "The sum of two positive numbers is always positive"
  • \n
\n\n

The framework (e.g., FsCheck) generates dozens and hundreds of random inputs and checks that the property holds for all of them. If a counterexample is found, the test fails, and you get the specific values that broke the code.

\n\n

Unlike unit tests, you don't write Assert.AreEqual(3, Add(1,2)). You write Assert(x + y == y + x) — and test commutativity for thousands of number pairs.

\n\n

Difference from Regular Unit Tests

\n\n\n\n\n\n\n\n
Unit TestsProperty-Based Tests
Check specific examplesCheck general laws
Data is defined by the developerData is generated by the framework
Miss edge casesAutomatically explore boundaries
Easy to readRequire abstract thinking
\n\n

FsCheck Library: Your Main Tool

\n\n

In the C# world, the de facto standard for property-based testing is FsCheck (originally a port of the Haskell library QuickCheck). It integrates with xUnit, NUnit, and MSTest.

\n\n

Installation is simple:

\n
dotnet add package FsCheck\ndotnet add package FsCheck.Xunit  // for xUnit integration
\n\n

FsCheck can generate random data for primitives (int, string, float), lists, arrays, tuples, and even custom types (via custom generators).

\n\n

Writing Your First Property-Based Test in C#

\n\n

Let's start simple: verify that integer addition is commutative.

\n\n
using FsCheck;\nusing FsCheck.Xunit;\n\npublic class AdditionTests\n{\n    [Property]\n    public bool Commutative_Addition(int x, int y)\n    {\n        return x + y == y + x;\n    }\n}
\n\n

Run the test. FsCheck will generate 100 random pairs of int (by default) and check the property. If no counterexample is found, the test is green. If we had made a mistake (e.g., wrote x - y == y - x), the test would fail with a specific example: (5, 3) — because 5 - 3 != 3 - 5.

\n\n

Breaking Down the Code

\n
    \n
  • [Property] — an attribute that tells FsCheck this is a property-based test.
  • \n
  • The method returns bool — if it returns false, the test fails.
  • \n
  • Parameters int x, int y — FsCheck will automatically substitute random values

Blogs

Book Recommendations