Autofixture: Freezing a mock does not override an injected instance

Created on 31 Jul 2018  ·  1Comment  ·  Source: AutoFixture/AutoFixture

Current Behaviour

When injecting two concrete instances, the second instance overrides the first.

When injecting a concrete instance, followed by a mocked instance, the second instance does not override the first.

This makes the idea of performing some tests which use a mock and some tests which use an implementation (using a test class constructor to share a fixture between tests) fairly awkward.

Expected Behaviour

When injecting two concrete instances, the second instance overrides the first.

When injecting a concrete instance, followed by a mocked instance, the second instance overrides the first.

Example of Expected Behaviour

```C#
using System.Collections.Generic;
using AutoFixture;
using AutoFixture.AutoMoq;
using Moq;
using Xunit;

namespace SomeNamespace
{
public class AutoFixtureTests
{
[Fact]
// Passes
public void Should_OverridePreviouslyInjectedString()
{
const string test1 = "test1";
const string test2 = "test2";

        var fixture = new Fixture();

        fixture.Inject(test1);
        fixture.Inject(test2);

        Assert.Equal(fixture.Create<string>(), test2);
    }

    [Fact]
    // Fails
    public void Should_OverridePreviouslyInjectedInstance()
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization());

        var sut1 = new List<int>();

        fixture.Inject<IList<int>>(sut1);
        fixture.Freeze<Mock<IList<int>>>();

        var sut2 = fixture.Create<IList<int>>();

        Assert.NotSame(sut1, sut2);
    }
}

}
```

question

Most helpful comment

Hi @charles-salmon,

Thank you for taking the time to report this.

The behaviour you're observing is _by design_. Allow me to explain. 🙂

If you look at the implementation of the Freeze<T> method:

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

You'll see that all it's doing is creating a specimen of T and injecting it into the fixture. Indeed, the Freeze method came about as a handy shortcut for this very operation. As @ploeh wrote in his post introducing the Freeze method back in 2010:

It turned out that we used this coding idiom so much that we decided to encapsulate it in a convenience method. After some debate we arrived at the name Freeze, because we essentially freeze a single anonymous variable in the fixture, bypassing the default algorithm for creating new instances.

Given that, it should come as no surprise that freezing the same type T as an injected instance yields the same instance.

Now, to address your point:

This makes the idea of performing some tests which use a mock and some tests which use an implementation (using a test class constructor to share a fixture between tests) fairly awkward.

Given that a fixture represents the _context_ in which a test runs, you certainly _can_ have multiple tests share the same fixture; however, this comes at the cost of mixing multiple—and possibly conflicting—concerns.

The xUnit Patterns book sums it up nicely:

The biggest issue with a Shared Fixture is that it can lead to "collisions" between tests possibly resulting in Erratic Tests, since tests may depend on the outcomes of other tests. Another issue is that a fixture designed to serve many tests is bound to be much more complicated than the Minimal Fixture needed for a single test.

This "collision" is exactly what happens when a test expects an object of type T to be a specific instance, while another test expects T to be a fake object.

Since I can't think of a test scenario where it makes sense for the same type T to both be a mock _and_ a concrete instance (although I'm happy to be proven wrong), I suggest you have these tests use different fixtures, each configured to serve their particular scenario.

>All comments

Hi @charles-salmon,

Thank you for taking the time to report this.

The behaviour you're observing is _by design_. Allow me to explain. 🙂

If you look at the implementation of the Freeze<T> method:

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

You'll see that all it's doing is creating a specimen of T and injecting it into the fixture. Indeed, the Freeze method came about as a handy shortcut for this very operation. As @ploeh wrote in his post introducing the Freeze method back in 2010:

It turned out that we used this coding idiom so much that we decided to encapsulate it in a convenience method. After some debate we arrived at the name Freeze, because we essentially freeze a single anonymous variable in the fixture, bypassing the default algorithm for creating new instances.

Given that, it should come as no surprise that freezing the same type T as an injected instance yields the same instance.

Now, to address your point:

This makes the idea of performing some tests which use a mock and some tests which use an implementation (using a test class constructor to share a fixture between tests) fairly awkward.

Given that a fixture represents the _context_ in which a test runs, you certainly _can_ have multiple tests share the same fixture; however, this comes at the cost of mixing multiple—and possibly conflicting—concerns.

The xUnit Patterns book sums it up nicely:

The biggest issue with a Shared Fixture is that it can lead to "collisions" between tests possibly resulting in Erratic Tests, since tests may depend on the outcomes of other tests. Another issue is that a fixture designed to serve many tests is bound to be much more complicated than the Minimal Fixture needed for a single test.

This "collision" is exactly what happens when a test expects an object of type T to be a specific instance, while another test expects T to be a fake object.

Since I can't think of a test scenario where it makes sense for the same type T to both be a mock _and_ a concrete instance (although I'm happy to be proven wrong), I suggest you have these tests use different fixtures, each configured to serve their particular scenario.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ecampidoglio picture ecampidoglio  ·  7Comments

zvirja picture zvirja  ·  8Comments

tiesmaster picture tiesmaster  ·  7Comments

zvirja picture zvirja  ·  4Comments

Ephasme picture Ephasme  ·  3Comments