# Moq: Linq to Mocks for .NET Unit Tests

> Moq is a .NET mocking library built on LINQ expression trees and Castle DynamicProxy. It skips the record/replay model, and this review covers what it does, how it installs from NuGet, and where it falls short.

**devlooped/moq** — The most popular and friendly mocking framework for .NET

- Repository: https://github.com/devlooped/moq
- Stars: 6,406 · Forks: 834
- Language: C#
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/devlooped-moq

## What Moq solves for .NET test authors

Unit tests for .NET code often need a stand-in for a dependency: a repository, an HTTP client wrapper, a service interface. Writing that stand-in by hand means a new class per dependency, with every member implemented and every call recorded manually. Moq generates the stand-in at runtime from the interface or class you want to fake. You declare behaviour with a lambda, hand the generated object to the code under test, and optionally assert which members were called. The README describes the target user plainly: developers who are not using a mocking library at all, or who find other implementations too complex, and who are "typically manually writing their own mocks". That is the gap Moq fills. It supports interfaces and classes, which matters because many .NET codebases depend on non-sealed classes with virtual members rather than pure interfaces.

## How LINQ expression trees replace record and replay

The mechanism is interception plus expression parsing. Moq uses Castle DynamicProxy internally, according to the README, to generate a proxy type that implements the interface or subclasses the class you specify. When you write mock.Setup(library => library.DownloadExists("2.0.0.0")), the lambda is not executed. It is compiled into a LINQ expression tree that Moq walks to extract the method and the argument values. That parsed expression becomes a rule stored on the mock. When the proxy object receives a matching call, it returns whatever the rule says. Verify works the same way in reverse: the expression identifies the member, and Moq checks its recorded invocations against the Times constraint. Because the lambda is a real C# expression, the compiler checks the method name and argument types. Rename a method in an interface and the test stops compiling instead of failing at runtime. The README calls this being "refactoring-friendly", and the mechanism is why. There is no separate expectation string to keep in sync.

## Installing Moq from NuGet and writing a first test

The README points to NuGet at nuget.org/packages/moq and to the project wiki Quickstart for examples. The package id is Moq. The README shows the API in use rather than a command line, so the first real step is adding the package to a test project through your package manager, then writing a test against the interface you want to fake. A minimal test using the API the README shows looks like this:

```csharp
var mock = new Mock<ILoveThisLibrary>();

mock.Setup(library => library.DownloadExists("2.0.0.0"))
    .Returns(true);

ILoveThisLibrary lovable = mock.Object;
bool download = lovable.DownloadExists("2.0.0.0");

mock.Verify(library => library.DownloadExists("2.0.0.0"), Times.AtMostOnce());
```

The mock.Object property returns the generated proxy. Calls you make on it hit the setup rules. Verify then checks the recorded calls against Times.AtMostOnce(). The README shows a second, shorter style it calls Linq to Mocks:

```csharp
ILoveThisLibrary lovable = Mock.Of<ILoveThisLibrary>(l =>
  l.DownloadExists("2.0.0.0") == true);

bool download = lovable.DownloadExists("2.0.0.0");
Assert.True(download);
```

Mock.Of returns a ready-made object whose behaviour comes from the boolean expression you pass. The README frames it as "from the universe of mocks, give me one whose behavior matches this expression". If you later need to verify interactions on an object you obtained this way, Mock.Get(lovable) recovers the mock wrapper.

## Where Moq stops being the right tool

Moq cannot proxy what DynamicProxy cannot intercept. Members must be virtual for class mocking, and the README does not document a workaround for non-virtual members. If your dependency is a sealed class or a static helper, Moq is the wrong instrument and you should refactor toward an interface instead. The default loose behaviour is another sharp edge: an unconfigured method that returns a reference type hands back a default value rather than throwing, so a test can pass while exercising a path you never set up. MockBehavior exists to change that, but the README only names the enumeration and does not spell out each mode, so read the API reference before relying on it. There is also a cost to the LINQ approach: setups are more verbose than a fluent stub built around a single call chain, and the expression-tree parsing means the library has to interpret lambdas that a plain delegate-based fake would never see. The README does not document rollback, migration or versioning policy, so treat upgrade behaviour as something to check in the changelog.

## Moq compared with NSubstitute and hand-written fakes

NSubstitute is the alternative most often weighed against Moq, and the difference is in the call syntax rather than the concept. Both generate substitutes at runtime. NSubstitute's API is built around extension methods on the substitute itself, so a setup reads as a call followed by a Returns, without the Setup wrapper and without an Object property to reach the proxy. Moq keeps the mock as a distinct object you configure and then unwrap. That separation is what makes Mock.Get and Mock.Of possible, and it is also what makes Moq's Linq to Mocks style work at all. Hand-written fakes sit at the other end: full control, no runtime proxy, no dependency in the test project, but one class per dependency and no verification support unless you build it. The README's own framing puts Moq between those poles, aimed at people who are writing fakes by hand and want the setup to be shorter without learning a record/replay model.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-21, so the codebase is receiving changes. The release history tells a different story about cadence: v4.20.72 is dated 2024-09-07, v4.20.71 is dated 2024-09-03, and v4.20.70 is dated 2023-11-28. Those are the recent releases listed for the package, and the gap between the 4.20.70 and 4.20.71 dates shows that tagged releases cluster rather than arrive steadily. A team pinning Moq should read changelog.md in the repository before moving a version, because the README does not describe a compatibility policy. On licensing, the repository ships a License.txt and the licence identifier is NOASSERTION, which means the automated classification did not match a standard SPDX identifier. This article cannot tell you what the terms are. Read License.txt at the repository root and, if the terms affect distribution of your test assemblies, get your own legal review.

## Conclusion

Adopt Moq when you write .NET unit tests and want a mocking library whose API is built on C# lambda expressions rather than record/replay. Do not adopt it if you are not on .NET, or if you need mocking to come from your test runner. Before committing, check the NuGet package page for the current version and supported frameworks, and read License.txt at the repository root, since the licence identifier is NOASSERTION and this article cannot tell you what terms apply.

## FAQ

### Is Moq safe to use?

That depends on the licence, and the repository's licence identifier is NOASSERTION, so the terms are not classified automatically. Read License.txt at the repository root. On the technical side, the README states that Moq uses Castle DynamicProxy internally as its interception mechanism.

### Does xUnit have mocking?

The README does not describe xUnit's own feature set. It does show Moq used alongside an assertion call, and it lists Moq as a separate package installed from NuGet at nuget.org/packages/moq, so mocking comes from Moq rather than from the test runner in that example.

### Is Moq a testing framework?

No. The README describes Moq as a mocking library for .NET that sets up and verifies dependencies for your tests. It is installed as a NuGet package and used inside tests written with whatever framework you already run.

### What are the disadvantages of Moq?

Class mocking requires members that DynamicProxy can intercept, and the README does not document a workaround for non-virtual members. Unconfigured methods return default values under the default behaviour, so a test can pass through a path you never set up. The README also does not document rollback or a versioning policy.

## Sources

- [devlooped/moq on GitHub](https://github.com/devlooped/moq)
- [Issues](https://github.com/devlooped/moq/issues)
- [README](https://github.com/devlooped/moq/blob/main/README.md)
- [Releases](https://github.com/devlooped/moq/releases)

---

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