Autofixture: Optionally disable caching for AutoMoq?

Created on 20 May 2016  ·  14Comments  ·  Source: AutoFixture/AutoFixture

When using an AutoConfiguredMoqCustomization, the value returned by the used fixture is cached, and the same value will be returned on each invocation (I'm not sure if this is done in MockType.ReturnsUsingContext or somewhere else, but I see a comment about it on line 104 there).

The only way I've found to override it is to pass a Frozen instance of the mock in question into the test method, and override the setup with a func invoking the fixture:

someMock.Setup(it => it.SomeMethodReturningAString()).Returns(() => fixture.Create<string>())

Is there any more generic/smarter way to configure the auto generated mocks to invoke the fixture each time a value is needed from AutoFixture, other than to manually setup each invocation?

enhancement good first issue

Most helpful comment

I admit that I thought the test doubles were configured to call back into AutoFixture in order to get a return value. AutoFixture does already have a lifetime management mechanism (via it's Freeze features), so I find it a bit surprising that AutoConfiguredMoqCustomization implements its own lifetime manager, and thereby overrides the control surface that AutoFixture itself provides.

All 14 comments

The idea behind caching the result value was to make all methods _pure_ by default, which is considered a good practice.

If the system under test expects a pure function, but is given an impure function, the test is likely to result in a false positive. E.g.

// This method will return the expected result *if* `GetInt` is pure.
int Double(IDependency dep) {
    return dep.GetInt() + dep.GetInt();
}

Assert.Equal(dep.GetInt * 2, Double(dep));

On the other hand, if the system under test does not assume purity, giving it a pure or impure function should make no difference.

Hence, defaulting to pure functions made sense to me when I implemented this feature.

Is there any more generic/smarter way to configure the auto generated mocks to invoke the fixture each time a value is needed from AutoFixture, other than to manually setup each invocation?

If you need to do this for _one_ method, but across multiple test, I'd put it in a reusable IConfiguration.

If you want to do this for all methods, across multiple tests, then you'll need a bit more work:

  • Define a new implementation of ReturnsUsingContext (IIRC, you can just copy the current implementation and remove line 104)
  • Redefine MockVirtualMethodsCommand and replace the call to ReturnsUsingContext with a call to your new method.
  • Redefine AutoConfiguredMoqCustomization and replace the instantiation of MockVirtualMethodsCommand with an instantiation of your new class.

We could also think of a way to make this behaviour configurable, but I'm not sure if the demand is high enough to justify this. Such a change should not be taken lightly, in my opinion - fine-grained customization can lead to accidental complexity. @ploeh, what are your thoughts on this?

I admit that I thought the test doubles were configured to call back into AutoFixture in order to get a return value. AutoFixture does already have a lifetime management mechanism (via it's Freeze features), so I find it a bit surprising that AutoConfiguredMoqCustomization implements its own lifetime manager, and thereby overrides the control surface that AutoFixture itself provides.

That's a very good point, I never thought about Freeze that way. Changing the customization's behaviour now would be a breaking change, I believe... do you think it should be changed in AutoFixture v4?

Is it behaviour we've documented or somehow 'promised' in tests?

Surprisingly, no. I was pretty sure I had covered this, but it appears I didn't. At least I couldn't find any test that covers this, and removing that line did not cause any test to fail. However, IMO, it still is observable behavior, and there's likely to be code that relies on this...

Fair point. Could it be a configuration value that we set to one value now, and then switch it when we transition to AutoFixture 4?

Agreed. In this context, what exactly do you mean by "configuration value"? Would lifting it to a const inside the MockType class suffice? E.g., private const bool cacheReturnValues = true and then if(cacheReturnValues) /**/

It was a bit of a throwaway comment, I admit, so I don't know if it'd be practically possible without too many changes. What I meant, though, was this:

@andreasnilsen would like to change the behaviour now, but we're concerned that it'd be a breaking change. If we make the behaviour configurable, then we'd give @andreasnilsen a way to change the behaviour now, while we don't break any other clients.

When we introduce AutoFixture 4, we change the default configuration, so that the default behaviour then is that return values aren't cached. Or perhaps we simply remove that option...

Something like a boolean cacheReturnValues could be one way of doing it, but we'd have to enable clients to change the value, so it can't be private.

(Also, unless we're absolutely certain that there's only going to be exactly two values, we should consider an enum instead of a bool.)

Ah, I first thought you meant some internal flag that was easy to spot and change in v4.

The first two approaches that come to mind are:

  • Simply add a boolean parameter (optional, for backwards compatibility) to the constructor of AutoConfiguredMoqCustomization, which would then be propagated down to MockVirtualMethodsCommand and to the internal MockType.ReturnsUsingContext. This seems:

    1. a bit convoluted and

    2. too _ad hoc_. If we wanted to add more configuration parameters to the customization, the constructor would become too complex and hard to use/maintain.

  • Use the parameter object pattern to solve issue (ii) above.

I'm wary of making design decisions that we might regret and be stuck with later, so your expertise/experience maintaining this project would be highly appreciated.

I was thinking something like a Strategy...

Ah yes, of course! I guess I was fixated on a "configuration value" and forgot to take a step back.

I'm sorry for the late reply, I've been swamped - I'll take a look at this soon and come back with a design proposal.

Recently we have performed the customization refactoring to use properties for the customization tweaking. Potentially, this feature could be controlled like following (find the better setting name):
c# new AutoMoqCustomization { CacheCallResults = false }

Under the hood we could implement that via different strategy like that has been advised above.

Marking with a jump in tag, as it should be relatively simple to implement this.

@zvirja could you help me out a bit and I can work on this one. I just don’t know where to start :)

@micheleissa Thanks for your interest! I would suggest just reading the AutoMoq source code and debugging it to understand the internal mechanics. It's very small, so it shouldn't take much time...

If you have more specific question, please ask 😉

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zvirja picture zvirja  ·  8Comments

joelleortiz picture joelleortiz  ·  4Comments

JoshKeegan picture JoshKeegan  ·  6Comments

tomasaschan picture tomasaschan  ·  3Comments

ploeh picture ploeh  ·  3Comments