Search code examples
xunit.netautofixture

How to create Mock classes in AutoDataAttribute subclasses?


I currently have a class called ExampleViewModelAttribute which derives from TestViewModelDataAttribute which is class derived from AutoDataAttribute class.

public class TestViewModelDataAttribute : AutoDataAttribute
{
    public TestViewModelDataAttribute()
        : this(new Fixture())
    {

    }

    public TestViewModelDataAttribute(IFixture fixture)
        : base(fixture)
    {
        Fixture.Customize(new ViewModelsCustomization());
        Fixture.Inject(Fixture);
    }
}


public class ExampleViewModelAutoDataAttribute : TestViewModelAutoDataAttribute
{
    public ExampleViewModelAutoDataAttribute()
    {
        var someExampleMock = Fixture.Create<Mock<ISomeExampleMock>>();
        Fixture.Inject(someExampleMock);
    }
}

My problem, is I keep getting a warning "Fixture is created lazily for the performance efficiency, so this property is deprecated as it activates the fixture immediately. " + "If you need to customize the fixture, do that in the factory method passed to the constructor."

How can I fix this warning? I want to inject the mock classes in the fixture, I only got one answer that helps me fix the base class warning but I need to fix injecting the mock classes as well.

Fix for base class

public class TestViewModelDataAttribute : AutoDataAttribute
{
    public TestViewModelDataAttribute() : base(() =>
    {
        var fixture = new Fixture().Customize(new CompositeCustomization(
            new AutoMoqCustomization(),
            new SupportMutableValueTypesCustomization()));

        return fixture;
    })
    {
    }
}

which I got from the following answer When setting up a custom AutoDataAttribute for auto mocking, what's the proper syntax to tell AutoFixture to ignore all recursive structures?

But since I use a property of Fixture in the derived class I still get errors. How should I fix this? Thanks


Solution

  • You should not use the Fixture property from the AutoDataAttribute, it will likely be removed in version 5.

    If you're trying to setup the mock before it is being injected in the test you can try to create a customization that does that.

    public class MockValuesSetupCustomization : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            var myMock = fixture.Freeze<Mock<ISomeExampleMock>>();
            myMock.Setup(x => x.DoSomething()).Returns("something");
        }
    }
    

    When you customize your autodata attribute you can customize the fixture using this customization.

    public class TestViewModelDataAttribute : AutoDataAttribute
    {
        public TestViewModelDataAttribute()
           : base(() => new Fixture()
                .Customize(
                    new CompositeCustomization(
                        new AutoMoqCustomization(),
                        new SupportMutableValueTypesCustomization(),
                        new MockValuesSetupCustomization())))
        {
        }
    }
    

    If you simply need some dependency to resolve the Mock<ISomeExampleMock> then you need not do anything because the AutoMoqCustomization will automatically create mocks for any interfaces. You can then access these injected mocks by freezing them in the test method parameters.

    Assuming you're using xUnit, your test will look like this.

    [Theory]
    [TestViewModelData]
    public void ShouldReturnExpectedResult(
        [Frozen] Mock<ISomeExampleMock> someExampleMock,
        ClassUnderTest sut)
    {
        sut.DoStuff();
    
        someExampleMock.Verify(x => x.DoSomething(), Times.Once);
    }