Moq Techniques: How to Pick the Best Syntax when Configuring Your Mocks
Tags: csharp, dotnet, testing, tutorial
Published: 2023-07-05 14:20:00

We briefly looked at creating testing mocks in an earlier part of this series. The focus at the time was on the concept of mocking, and to not get side-tracked, we used one of the simplest ways to create and set up our mock. But when we come to test more complex real-world logic, we may want additional configuration options. This week, we’ll look at the two syntax options we can use to set up mocks with Moq, along with their pros and cons.

## A Modern Approach to Declaring and Setting Up Mocks

When we previously introduced mocking, we created mocks using [LINQ to Mocks](https://github.com/Moq/moq4/wiki/Quickstart#linq-to-mocks). This (relatively) new syntax should be fairly intuitive if you’re used to writing LINQ queries using Method Syntax, i.e. with extension methods like `First`, `Single`, and `Where`. To refresh our memories, here’s how we declared our mock.

``` csharp
var multiplicationService = Mock.Of<IMultiplicationService>(s =>
    s.Square(3) == 9 &&
    s.Square(4) == 16);
```

When using LINQ to Mocks, the return value (from `Mock.Of`) is the mocked entity. In this example, this is an `IMultiplicationService` that’s ready to be used as a method argument or set as a property value.

## A Fluent Alternative to LINQ to Mocks

We can also create and set up mocks using a fluent syntax. To achieve the same result as in our previous LINQ to Mocks example, we can use the following code.

``` csharp
var multiplicationService = new Mock<IMultiplicationService>();

multiplicationService
    .Setup(s => s.Square(3))
    .Returns(9);

multiplicationService
    .Setup(s => s.Square(4))
    .Returns(16);
```

In this case, `multiplicationService` is an object representing the mock, rather than the mocked entity. We can easily get an `IMultiplicationService` to use in our tests from the mock’s `Object` property. Here, this would be `multiplicationService.Object`.

While more verbose than LINQ to Mocks, it’s still easy to see what’s going on. But that still leaves one question: why would we want to write more code to achieve the same result?

To better explain the answer, let’s first explore another concept related to setting up mocks.

## When Arguments Just Don’t Matter

In the previous examples, the argument for our mocked method mattered; the return value was dependent on the provided data:

`9` was returned when `Square` was called with `3`.

`16` was returned when `Square` was called with `4`.

In some test contexts, a mock’s method arguments are irrelevant – we just need it to return something to use in the test. We can use `It.IsAny<T>()` in these situations, specifying a generic type that matches the parameter type. For example, imagine we have the following code.

``` csharp
public class MyObject
{
    public int Id { get; set; }
}

public interface IObjectRepository
{
    MyObject GetObject(int id);
}
```

Suppose we have a test where an `IObjectRepository` should return a `MyObject` regardless of the ID passed to it. We can set up a mock to do this with the following code:

``` csharp
var repository = Mock.Of<IObjectRepository>(r =>
    r.GetObject(It.IsAny<int>()) == new MyObject());
```

We use `It.IsAny<int>()` in place of an actual integer while setting up the mock. The results in an `IObjectRepository` that always returns the specified `MyObject` regardless of the value of `id`.

## Advantages of the Fluent Syntax

Returning to our previous question: why might we choose to write more code for the same result? The answer is that the results are subtly different, and we have greater control with the fluent syntax. In the following test, we retrieve a `MyObject` twice. We then check that they refer to different object instances.

``` csharp
[Test]
public void ReturnedObjectIsNewInstance()
{
    // Arrange

    var repository = Mock.Of<IObjectRepository>(r =>
        r.GetObject(It.IsAny<int>()) == new MyObject());

    // Act

    var obj1 = repository.GetObject(1);
    var obj2 = repository.GetObject(2);

    // Assert

    Assert.IsTrue(obj1 != obj2);
}
```

It might come as a surprise that this test fails:

```
Expected: True
But was:  False
```

Calling a method mocked with LINQ to Mocks returns the same value on successive invocations. While testing a mock isn’t something we’d do in a real project, the result is relevant if the logic in a test calls a mocked method more than once. If it’s important for a mock to return a new instance per invocation, we might consider using the fluent syntax:

``` csharp
[Test]
public void ReturnedObjectIsNewInstance()
{
    // Arrange

    var repositoryMock = new Mock<IObjectRepository>();

    repositoryMock
        .Setup(r => r.GetObject(It.IsAny<int>()))
        .Returns<int>(i => new MyObject());

    var repository = repositoryMock.Object;

    // Act

    var obj1 = repository.GetObject(1);
    var obj2 = repository.GetObject(2);

    // Assert

    Assert.IsTrue(obj1 != obj2);
}
```

Running this test passes.

## Summary
Moq lets you set up mocks with one of two syntaxes, each with advantages. LINQ to Mocks is modern, concise, and familiar. The fluent style offers more control.

When using LINQ to Mocks, you can easily declare and set up a mock with code similar to writing a LINQ query using Method Syntax. While succinct, the resulting mocks might not be suitable depending on your test – methods configured with return values will return the same instance on every invocation. If this is a problem, consider using the fluent syntax – while more verbose, your mocks will be much more flexible.

Writing less code often makes things simpler. But simplicity cannot be a substitute for correctness. By understanding your options when setting up your mocks, you can make the best choice for the task at hand.

---

Thanks for reading!

Software development evolves quickly. But we can all help each other learn. By sharing, we all grow together.

I write stories, tips, and insights as an Angular/C# developer.

If you’d like to never miss an issue, you’re invited to [subscribe](https://webdeveloperdiary.substack.com/?sd=pf) for free for more articles like this, delivered straight to your inbox (link goes to Substack).