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.
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.
```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);
}
}
}
```
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.
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:You'll see that all it's doing is creating a specimen of
T
and injecting it into the fixture. Indeed, theFreeze
method came about as a handy shortcut for this very operation. As @ploeh wrote in his post introducing the Freeze method back in 2010: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:
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:
This "collision" is exactly what happens when a test expects an object of type
T
to be a specific instance, while another test expectsT
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.