Autofixture: Get instance of inner Interface created by AutoMoqData.

Created on 26 Apr 2018  ·  8Comments  ·  Source: AutoFixture/AutoFixture

Hi,

I'm trying to get the instance of the the inner Mocked Interface created by AutoMoqData to setup the interface.

Is there a way to do something like this

[Theory, AutoMoqData]
public void Dummy(IFixture fixture, ComplexClassWithInnerInterface sut)
{
    fixture.GetInstance<IInnerInterfaceMockCreatedByAutoMoqData>().Setup(x => x.Method).Result(something);

    Assert.Equal(String.Empty, String.Empty);
}

Thanks

question

Most helpful comment

Thanks @xlecoustillier for the great answer. Basically, I'd suggest to do the same as I'm constantly following this pattern in my tests.

But for 30 interfaces it's pretty ugly to have them in method parameters.

Well, this argument looks a bit weird. Probably, it's something wrong with the design of tested code if you need to configure 30 dependencies to make a scenario 😟 I'm 99% @ploeh would suggest you to review the code first before proceeding further, as per his advice it's recommended to have max 3-4 dependencies 😅

So it seems impossible to get auto created mocks from the container of the fixture. They are not injected by default so if fixture had a GetInstance like method, it will not return anything for the auto created mocks.

I'm not 100% sure I understood the entire message clearly, but from what I got you are right. By default all the generated objects are transient and fixture doesn't preserve them. If you wish to make the particular object a singleton, you should use the fixture.Freeze<>() API or [Frozen] attribute or any other suitable API.
The existing default behavior was designed to cover the common scenarios and in most cases you _don't want_ to have the same object per type.

If you are still looking for the help from our side, please provide more exact requirement you have. Better, share enough code to demonstrate the current limitations and goal you would like to achieve - that will help to sync better 😉

Thanks.

All 8 comments

try

Mock.Get(sut).Setup(x => x.Method).Result(something);

You will get Object instance was not created by Moq. accessing sut.

This will actually work if interface is in a public property.
Mock.Get(sut.InnerInterface).Setup(x => x.Method).Result(something);

But what if the interface is is mocked and constructor injected, registered in the IoC container but not accessible in sut with a public property?

In this case you'll have to freeze the mock to ensure that the instance you generate will also be injected into the sut:

[Theory, AutoMoqData]
public void Dummy(
    IFixture fixture, 
    [Frozen]Mock<YourInnerInterface> innerInterfaceMock,
    ComplexClassWithInnerInterface sut)
{
    innerInterfaceMock.Setup(x => x.Method).Result(something);
    sut.DoSomething();
    Assert.Equal(String.Empty, String.Empty);
}

Be careful to always create the frozen mocks before the sut so that they already exist when the sut gets created and therefore get correctly injected.

See ploeh'sblog for reference.

Hi,
I was already doing that. But for 30 interfaces it's pretty ugly to have them in method parameters.
Your code reminded me that AutoMoqData does not freeze all mocked interfaces. So it seems impossible to get auto created mocks from the container of the fixture. They are not injected by default so if fixture had a GetInstance like method, it will not return anything for the auto created mocks. That's why I get duplicates if I freeze the mock with the fixture instance. The only way I see It would work is if the sut could be updated with the later frozen mocks, but that would be ugly. The easy way is to use AutoMoqData to create the IFixture, freeze and setup mocks in the test method, then create sut. With this setup I can create a reusable helper method to freeze and setup mocks.

Thanks

Thanks @xlecoustillier for the great answer. Basically, I'd suggest to do the same as I'm constantly following this pattern in my tests.

But for 30 interfaces it's pretty ugly to have them in method parameters.

Well, this argument looks a bit weird. Probably, it's something wrong with the design of tested code if you need to configure 30 dependencies to make a scenario 😟 I'm 99% @ploeh would suggest you to review the code first before proceeding further, as per his advice it's recommended to have max 3-4 dependencies 😅

So it seems impossible to get auto created mocks from the container of the fixture. They are not injected by default so if fixture had a GetInstance like method, it will not return anything for the auto created mocks.

I'm not 100% sure I understood the entire message clearly, but from what I got you are right. By default all the generated objects are transient and fixture doesn't preserve them. If you wish to make the particular object a singleton, you should use the fixture.Freeze<>() API or [Frozen] attribute or any other suitable API.
The existing default behavior was designed to cover the common scenarios and in most cases you _don't want_ to have the same object per type.

If you are still looking for the help from our side, please provide more exact requirement you have. Better, share enough code to demonstrate the current limitations and goal you would like to achieve - that will help to sync better 😉

Thanks.

Yes, I would suggest that 30 dependencies are too many.

Regarding getting at the injected dependencies, using the [Frozen] attribute, as @xlecoustillier suggests, is one option, and in fact the reason that attribute originally exists.

Using Mock.Get(sut.Dep1) is also an option I often use.

But what if the interface is [...] constructor injected [...] but not accessible in sut with a public property?

Why not expose it as a property, then? What you compose, you can also expose.. It doesn't break encapsulation to expose it.

I feel like adding on @ploeh by specifying that the best approach is to expose dependencies as class properties without enriching your abstraction which would be nothing more that leaking your implementation!

@malylemire1 Closing this as it seems no further assistance is required. Please let us know if there is anything else we can help you with 😉

Thanks for one more time for raising the question! 👍

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joelleortiz picture joelleortiz  ·  4Comments

josh-degraw picture josh-degraw  ·  4Comments

TroyHouston picture TroyHouston  ·  6Comments

ecampidoglio picture ecampidoglio  ·  7Comments

ploeh picture ploeh  ·  7Comments