Search code examples
c#unit-testingxunitautofixtureautomoq

How to Run Unit Tests When using inline data with Automoq and Autofixture


I created some unit tests on an existing project. I am using AutoMoq to inject data into some of the tests. Upon running the test, it complains of recursion error. I solved the error using the below code:

public sealed class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(() => new Fixture().Customize(new DomainCustomization()))
    {
    }
}

public class OmitRecursionCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b =>
        fixture.Behaviors.Remove(b));
        fixture.Behaviors.Add(new OmitOnRecursionBehavior());
    }
}

public class DomainCustomization : CompositeCustomization
{
    public DomainCustomization()
        : base(
            new AutoMoqCustomization(),
            new SupportMutableValueTypesCustomization(),
            new OmitRecursionCustomization())
    {
    }
}

After solving the recursion error, the test won't run. The debug output keeps saying the thread has exited. I then created some sample classes to test my setup and they all run, except the existing project classes tests.

A sample of a class I am writing test for is this:

public partial class BusinessContact
{
    public int BusinessContactId { get; set; }
    public int BusinessId { get; set; }
    public int ContactId { get; set; }
    public int? AddressId { get; set; }
    public int? EmailId { get; set; }
    public BusinessContactType.TypeID BusinessContactTypeId { get; set; }

    [Column(TypeName = "smalldatetime")]
    public DateTime DateLastModified { get; set; }

    [StringLength(450)]
    public string ModifiedByUserId { get; set; }

    [ForeignKey("AddressId")]
    [InverseProperty("BusinessContact")]
    public virtual Address Address { get; set; }

    [ForeignKey("BusinessId")]
    [InverseProperty("BusinessContact")]
    public virtual Business Business { get; set; }

    [ForeignKey("BusinessContactTypeId")]
    [InverseProperty("BusinessContact")]
    public virtual BusinessContactType BusinessContactType { get; set; }

    [ForeignKey("ContactId")]
    [InverseProperty("BusinessContact")]
    public virtual Contact Contact { get; set; }

    [ForeignKey("EmailId")]
    [InverseProperty("BusinessContact")]
    public virtual Email Email { get; set; }
}

A sample test for the above class is this:

    [Theory]
    [AutoMoqData]
    public void ValidateMandatoryField(BusinessContact _sut)
    {
        Assert.NotNull(_sut.BusinessId);
        Assert.True(_sut.BusinessId > 0);
    }

I intend to send multiple inline data where I can set the value some of the class properties to test the behaviours I am looking for.

Could someone please enlighten me on what might be wrong.

Thank you.


Solution

  • This post https://stackoverflow.com/a/70957998/3036650 solved my challenge on this question. The issue has to do with circular reference caused when using Entity framework. So the code can totally replace or be added to the content of customize method in the OmitRecursionCustomization class. The class looks like this now:

        {
            public void Customize(IFixture fixture)
            {
                fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b =>
                fixture.Behaviors.Remove(b));
                fixture.Behaviors.Add(new OmitOnRecursionBehavior());
                fixture.Customizations.Add(new IgnoreVirtualMembers());
            }
        }
    

    and it is used as follows:

    var fixture = new Fixture().Customize(new IgnoreVirtualMembersCustomisation());