# FakeItEasy drops the mock and stub vocabulary from .NET tests

> A dynamic fake library for .NET whose central claim is that a fake is just a fake and the test decides whether it behaves as a mock or a stub. The README is short, and the documentation site is where the detail lives.

**FakeItEasy/FakeItEasy** — The easy mocking library for .NET

- Repository: https://github.com/FakeItEasy/FakeItEasy
- Website: https://fakeiteasy.github.io
- Stars: 1,855 · Forks: 181
- Language: C#
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/fakeiteasy-fakeiteasy

## One type, and the vocabulary follows from the use

FakeItEasy describes itself as a .NET dynamic fake library for creating all types of fake objects, mocks and stubs, and then immediately argues against that list. Its first stated design goal is easier semantics where all fake objects are just that, fakes, and the use of the fakes determines whether they are mocks or stubs.

That is a real distinction in test design, not a naming preference. The mock and stub labels come from xUnit's test taxonomy and are applied to objects at creation time in some libraries, which means the creator has to predict how the object will be used. FakeItEasy pushes that decision to the point of use: create the same thing with A.Fake, then whether it is a mock or a stub is determined by whether you set expectations on it.

The remaining goals follow from that. The interface is described as context-aware and fluent so it guides the developer rather than requiring recall of overload names, it is designed for ease of use, and there is full compatibility with both C# and VB.Net.

The VB.Net point is the one that distinguishes this library in practice, and it is not a minor bullet.

## Three calls cover the whole example

The README's example is worth reading in full because it shows configuration and assertion using identical syntax, which is the design claim made concrete.

```c#
var shop = A.Fake<ICandyShop>();

var lollipop = new Lollipop();
A.CallTo(() => shop.GetTopSellingCandy()).Returns(lollipop);

var customer = new SweetTooth();
customer.BuyTastiestCandy(shop);

A.CallTo(() => shop.BuyCandy(lollipop)).MustHaveHappened();
```

A.Fake creates the object for any type, including an interface like ICandyShop, with no setup step. A.CallTo takes a lambda describing the call, and that lambda is the unit of configuration: Returns arranges a return value, and MustHaveHappened verifies that the call occurred.

The lambda is what makes the interface context-aware. Because the argument is an expression rather than a string method name, the compiler checks that the method exists and that the argument types line up, and the configuration reads the same way the assertion does. Asserting uses the same syntax as configuring calls, which is the sentence the README puts in the example as a comment.

## A fake for all types, including the ones that are hard

The description says the library creates fakes for all types, and the README's stated intent is that no mocks or stubs exist, everything is a fake. Combined with the dynamic framing, that means the library builds implementations at run time rather than asking you to write and maintain a test double class.

The one thing the README does not tell you is how that works under the hood, and it is worth being honest about that boundary. The documentation site carries a quickstart and full documentation, and the README sends you there rather than describing interception, proxy generation or which members are faked. So if your decision depends on the mechanism, such as whether you can fake a sealed class or a non-virtual member, you have to read the documentation pages rather than infer from the repository.

What can be said from the repository layout is that this is a substantial codebase rather than a wrapper over something else. There are src/ and tests/ directories, docs/ and recipes/ directories, plus a shared tools directory, a solution file and three platform build scripts.

## Three build scripts for three shells, and one solution

The top-level entries describe how the project itself is developed. There are build.sh, build.cmd and build.ps1 side by side, providing common build entry points, and a how-to-build.md at the root pointing at the details. Directory.Build.props holds shared MSBuild properties across the projects, FakeItEasy.sln is the solution, and a.globalconfig sits at the root for analyzer or formatter configuration.

There is a profiles/ directory, which in this ecosystem is usually the place for per-target or per-scenario configuration, and a recipes/ directory separate from docs/, which suggests worked examples kept apart from reference documentation. A.git-blame-ignore-revs file is present, the standard way to exclude large mechanical commits such as reformatting or version bumps from blame history, and.gitattributes and.mailmap handle line endings and author identity.

CI is a GitHub Actions workflow named ci.yml running against the master branch, which is the default branch here.

None of that is exotic, but it does mean the project follows the conventions of a mature.NET repository, including the parts most small libraries skip.

## Three target frameworks, and the old one is still there

The NuGet packages target.NET Framework 4.6.2,.NET 8.0 and.NET 10.0. That combination is the practical constraint to plan around.

Keeping.NET Framework 4.6.2 in the list may matter when the assembly under test targets.NET Framework. If you are on modern.NET only, the entry is dead weight and costs you nothing.

The two modern targets bracket several years of.NET, so a single package reference covers current LTS and current releases without conditional references.

The README also links the NuGet profile on nuget.org alongside the packages themselves, so the exact published version list is one click away rather than something to guess at.

## Version 9 is recent and the 8.x line goes back years

The release history shows two recent tags and one much older one: 9.0.0 and 9.0.1 in January 2026, and 8.3.0 from June 2024.

A major version bump in a library like this signals a compatibility break, so anything written against 8.x needs a migration pass rather than a version bump. 

The last push was on 2026-10-07 and the repository is not archived, so work continues on master after the January release.

The licence is MIT, in License.txt at the root. For a test-only library that is rarely the interesting question, but it does mean the library can be vendored into a closed-source test project without an exception.

## What the README does not tell you

This README is unusually short, and the absences are worth stating rather than working around. It does not show how to assert arguments, how to verify a call happened a specific number of times, how to make a property or field return a value, or how to inject a fake into the code under test.

It also does not describe the difference between creating a fake of a class and of an interface, does not mention any behaviour control on creation, and does not discuss thread safety or lifetime.

For a library whose selling point is that its API is easy to learn, that is a notable choice. The justification is visible in the resource list: the website, a quickstart page, full documentation, a chat room on Gitter and the NuGet profile. The README's job is to convince, and the documentation's job is to teach.

If you are evaluating quickly, read the quickstart rather than the README, and expect the detail you need about assertions and injection to be in the documentation pages rather than in this repository.

## Conclusion

Adopt FakeItEasy if your .NET test suite is shared with VB.NET developers or if your team keeps tripping over the mock versus stub distinction, since the library's whole surface is one configuration verb used for both setup and assertion. Do not expect the README to teach you: it documents three API calls and links out for everything else, so budget time for the quickstart and documentation pages. Verify first which target framework you need, because packages cover .NET Framework 4.6.2, .NET 8.0 and .NET 10.0, and confirm your version resolves to the 9.x line released in January 2026 rather than the older 8.3.0.

## FAQ

### What is the difference between a fake, a mock and a stub in FakeItEasy?

FakeItEasy only creates fakes. The README states that all fake objects are just that, fakes, and that the use of the fakes determines whether they are mocks or stubs. You create one with A.Fake and set up expectations with A.CallTo only if the test needs them.

### Which .NET versions does FakeItEasy support?

The NuGet packages target .NET Framework 4.6.2, .NET 8.0 and .NET 10.0. The README links the NuGet profile for the exact published package list.

### How do I verify a call happened in FakeItEasy?

Using the same syntax as configuration: write the call in a lambda passed to A.CallTo and finish with MustHaveHappened, as in A.CallTo(() => shop.BuyCandy(lollipop)).MustHaveHappened(). The README notes that asserting uses the same syntax as configuring calls.

### Does FakeItEasy work with VB.NET?

Yes. Full compatibility with both C# and VB.Net is one of the four stated design goals alongside easier semantics, a context-aware fluent interface and ease of use.

## Sources

- [FakeItEasy/FakeItEasy on GitHub](https://github.com/FakeItEasy/FakeItEasy)
- [License: MIT](https://github.com/FakeItEasy/FakeItEasy/blob/master/LICENSE)
- [Project website](https://fakeiteasy.github.io)
- [README](https://github.com/FakeItEasy/FakeItEasy/blob/master/README.md)
- [Releases](https://github.com/FakeItEasy/FakeItEasy/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fakeiteasy-fakeiteasy
