6

Moq does not make recursive mocks by default. That is, for members without expectations on a mock, Moq returns default values. For example, given:

public interface IFoo
{
    Bar Bar();
}

and

public class Bar
{
}

then:

[TestMethod]
public void RecursiveMocksAreDisabledByDefaultInMoq()
{
    var foo = new Mock<IFoo>().Object;
    Assert.IsNull(foo.Bar());
}

However, in AutoFixture.AutoMoq, recursive mocks are enabled by default, as in:

[TestMethod]
public void RecursiveMocksAreEnabledByDefaultInAutoFixture()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var foo = fixture.Create<IFoo>();
    Assert.IsNotNull(foo.Bar());
}

Why is that? And, how to turn off automatic recursive mocks in AutoFixture.AutoMoq?

Thanks

Moq.3.1.416.3
AutoFixture.AutoMoq.3.16.5
beluchin
  • 12,047
  • 4
  • 24
  • 35
  • 1
    You might find elements of [this discussion pertaining to the default return value in AutoFoq](https://foq.codeplex.com/discussions/470568) useful - AutoFoq doesn't OOTB change Foq behaviour (resulting in `null` return values from methods OOTB). I also strongly recommend AutoFoq and Foq - however I appreciate changing mocking libs isnt something you 'just do'. I personally for the longest time didnt understand how a mocking library could be so significantly more usable than Moq and discounted it for a long time despite being aware of it. (NB I write most of my tests in F#) – Ruben Bartelink Feb 21 '14 at 05:56
  • 3
    Because "AutoFixture is an opinionated library, and one of the opinions it holds is that nulls are invalid return values." http://stackoverflow.com/a/18170070/126014 – Mark Seemann Feb 21 '14 at 06:59
  • 1
    See also https://autofixture.codeplex.com/workitem/4261 – Mark Seemann Feb 21 '14 at 06:59
  • @MarkSeemann am aware of the cited post. AutoFoq defaults to returning nulls. AutoMoq returns recursive Mocks. There is an inconsistency. That's my main point. As you know I have no problem with Opinionated design (esp when you explain things which you normally do fantastically) and love, appreciate and use Auto* very much on a daily basis – Ruben Bartelink Feb 21 '14 at 08:23
  • Yes... Until [the next major release](https://github.com/AutoFixture/AutoFixture/issues/214), where AutoFoq will use [Foq's new return strategy](https://foq.codeplex.com/discussions/470568), it currently uses Foq's 1.x behaviour (returning `null` for properties and methods that have not been explicitly setup). – Nikos Baxevanis Feb 21 '14 at 11:03
  • @NikosBaxevanis Ah, cool. Wasnt aware that had been agreed (or if I was I forgot :). I personally am happy with things falling that way. Beluchin: I hope you agree this makes sense. – Ruben Bartelink Feb 21 '14 at 19:00
  • @MarkSeemann Very sorry, for some reason I skipped over you stating that the opinion was that `null`s are invalid return values and hence replied as if you hadn't made that clear. Changing the AutoFoq strategy to have Foq also source values for non-mocks from AF closes that loop excellently. (Now I just have to hope you start dogfooding AutoFoq and run into [a clash between it's and your meanings of `verify`](https://twitter.com/rbartelink/status/433346161223557120) :P) – Ruben Bartelink Feb 21 '14 at 19:08
  • I am ok with the approach of returning recursive mocks by default. It would be nice, though, to have an easy way to disable it. – beluchin Feb 21 '14 at 22:07

1 Answers1

3

The comments to the question ought to answer the original question of why, but then there's the follow-up comment:

It would be nice, though, to have an easy way to disable [recursive mocks].

It's not that hard to do. If you look at the implementation of AutoMoqCustomization, it's the use of MockPostProcessor that turns on recursive mocks. If you don't want that, you can create your own Customization that doesn't do that:

public class AutoNonRecursiveMoqCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        if (fixture == null)
            throw new ArgumentNullException("fixture");

        fixture.Customizations.Add(
            new MethodInvoker(
                new MockConstructorQuery()));
        fixture.ResidueCollectors.Add(new MockRelay());
    }
}

MockPostprocessor also sets CallBase to true, so by omitting MockPostprocessor you also disable that CallBase setting.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736