Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using AutoFixture with Moq?

Using this structure.

public class User
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public virtual bool IsAdministrator()
    {
        return false;
    }
}

Is it possible to combine AutoFixture and Moq to accomplish the following?

  1. Ensure User.FirstName is auto-generated
  2. Ensure User.LastName is always "Smith" (literal)
  3. Ensure User.MiddleName is not populated (default)
  4. Ensure User.IsAdministrator() returns True
  5. Verify IsAdministrator() was called.

I know this seems so simple. Here's what I tried using AutoMoq.

var config = new AutoMoqCustomization() 
{ 
    ConfigureMembers = true 
};

var fixture = new AutoFixture.Fixture();
fixture.Customize(config);

fixture.Freeze<Mock<User>>()
    .Setup(x => x.IsAdministrator())
    .Returns(true);

var model = fixture.Build<User>()
    .With(x => x.LastName, "Smith")
    .Without(x => x.MiddleName)
    .Create();

But that is clearly wrong. :( I am sure the syntax is simple. Thank you for any help.

My goal: create an object with BOTH filled properties and mocked methods.

like image 520
Jerry Nixon Avatar asked Sep 05 '25 03:09

Jerry Nixon


1 Answers

The following achieves the requested goals

public void AutoFixture_Should_Fill_Poperties_And_Mock_Methods() {
    //Arrange
    AutoMoqCustomization config = new AutoMoqCustomization() {
        ConfigureMembers = true
    };

    IFixture fixture = new AutoFixture.Fixture().Customize(config);

    Mock<User> mock = new Mock<User>();
    mock
        .Setup(x => x.IsAdministrator())
        .Returns(true);

    User model = fixture.Build<User>()
        .FromSeed(s => mock.Object) //<-- 
        .With(x => x.LastName, "Smith")
        .Without(x => x.MiddleName)
        .Create();

    //Assert

    //Ensure User.FirstName is auto-generated
    model.FirstName.Should().NotBeNullOrEmpty();
    //Ensure User.LastName is always "Smith" (literal)
    model.LastName.Should().Be("Smith");
    //Ensure User.MiddleName is not populated (default)
    model.MiddleName.Should().BeNull();
    //Ensure User.IsAdministrator() returns True
    model.IsAdministrator().Should().BeTrue();
    //Verify IsAdministrator() was called.
    mock.Verify(_ => _.IsAdministrator());
}

An observation was that when using

Mock<User> mock = fixture.Freeze<Mock<User>>();

if would still populate the MiddleName property even though it was explicitly told Without for the build, but worked as desired when using

Mock<User> mock = new Mock<User>();

But if you were to explicitly set the member to return null

Mock<User> mock = fixture.Freeze<Mock<User>>(); // new Mock<User>();
mock
    .Setup(x => x.IsAdministrator())
    .Returns(true);

User model = fixture.Build<User>()
    .FromSeed(s => mock.Object)
    .With(x => x.LastName, "Smith")
    .With(x => x.MiddleName, (string)null) //<--
    .Create();

It worked.

Here is another variation of the test with a subject class that depends on the model to be injected.

[Test]
public void AutoFixture_Should_Fill_Poperties_And_Mock_Methods() {
    //Arrange
    AutoMoqCustomization config = new AutoMoqCustomization() {
        ConfigureMembers = true
    };

    IFixture fixture = new AutoFixture.Fixture().Customize(config);

    Mock<User> mock = new Mock<User>();
    mock
        .Setup(x => x.IsAdministrator())
        .Returns(true);

    User model = fixture.Freeze<User>(c => c
        .FromSeed(s => mock.Object)
        .With(x => x.LastName, "Smith")
        .With(x => x.MiddleName, (string)null)
    );

    //Act
    Subject subject = fixture.Create<Subject>();
    bool actual = subject.Act();

    //Assert

    //Ensure User.FirstName is auto-generated
    model.FirstName.Should().NotBeNullOrEmpty();
    //Ensure User.LastName is always "Smith" (literal)
    model.LastName.Should().Be("Smith");
    //Ensure User.MiddleName is not populated (default)
    model.MiddleName.Should().BeNull();
    //Ensure User.IsAdministrator() returns True
    actual.Should().BeTrue();
    //model.IsAdministrator().Should().BeTrue();
    //Verify IsAdministrator() was called.
    mock.Verify(_ => _.IsAdministrator());
}


public class Subject {
    private User model;

    public Subject(User model) {
        this.model = model;
    }

    public bool Act() => model.IsAdministrator();
}
like image 162
Nkosi Avatar answered Sep 08 '25 00:09

Nkosi