简体   繁体   中英

Unit test passes when in debug but fails randomly when run [xUnit + Automoq + Autofixture]

Moq setup doesn't work as expected using Automoq + Autofixture while running multiple test cases.

I created multiple test cases corresponding to my method. In my test run, random test failures occur with stating reason - System.InvalidOperationException: The test method expected 3 parameter values, but 1 parameter value was provided.

Code Setup -

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

        fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => fixture.Behaviors.Remove(b));
        fixture.Behaviors.Add(new OmitOnRecursionBehavior());

        return fixture;
    })
    {
    }
}
  • Theory Data Class
    public struct ExpectedValueTestData<TExpected>
    {
        public string Name;
        public Parameters Params;
        public TExpected ExpectedValue;

        public override string ToString()
        {
            return $"{this.Name}";
        }
    }

    public struct Parameters
    {
        public Campaign.Entities.Enum.RunningStatus currentStatus;
        public Campaign.Entities.Enum.RunningStatus updatedStatus;
        public Campaign.Entities.Enum.Application application;
    }

#region Test data
    public class ValidValueTests : TheoryData<ExpectedValueTestData<bool>>
    {
        public ValidValueTests()
        {
            this.Add(new ExpectedValueTestData<bool>
            {
                Name = @"SetRunningStatusActiveTest - valid call for xyz",
                Params = new Parameters
                {
                    currentStatus = RunningStatus.Daily_Goal_Reached,
                    updatedStatus = RunningStatus.Running,
                    application = Application.XYZ,
                },
                ExpectedValue = true,
            });
        }
    }
  • Test Case Class

public class SetRunningStatusActiveTestCase
{
    #region Theories
    [Theory, AutoMoqData]
    [ClassData(typeof(ValidValueTests))]
    public async Task SetRunningStatusActiveTest_WhenValidCampaignExist(ExpectedValueTestData<bool> data, [Frozen] Mock<ICampaignRunningStatusRepo> campaignRunningStatusRepoMock, CampaignRunningJob sut)
    {
        campaignRunningStatusRepoMock.Setup(x => x.GetCampaignsOnRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => new List<int> { 1, 2, 3 }).Verifiable();
        campaignRunningStatusRepoMock.Setup(x => x.ConvertRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => 3);

        var actual = await sut.SetRunningStatusActive(data.Params.currentStatus, data.Params.updatedStatus, data.Params.application);
        Assert.Equal(data.ExpectedValue, actual);
        campaignRunningStatusRepoMock.Verify();
    }

    [Theory, AutoMoqData]
    [ClassData(typeof(ZeroCampaignsForUpdateTests))]
    public async Task SetRunningStatusActiveTest_WhenNoCampaignExist(ExpectedValueTestData<bool> data, [Frozen] Mock<ICampaignRunningStatusRepo> mockCampaignRunningStatusRepo1, CampaignRunningJob sut)
    {
        mockCampaignRunningStatusRepo1.Setup(x => x.GetCampaignsOnRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => new List<int> { });

        var actual = await sut.SetRunningStatusActive(data.Params.currentStatus, data.Params.updatedStatus, data.Params.application);
        Assert.Equal(data.ExpectedValue, actual);
    }

    [Theory, AutoMoqData]
    [ClassData(typeof(TestsThrowingException))]
    public async Task SetRunningStatusActiveTest_WhenThrowingException(TestThrowingExceptionData data, [Frozen] Mock<ICampaignRunningStatusRepo> mockCampaignRunningStatusRepo2, CampaignRunningJob sut)
    {
        mockCampaignRunningStatusRepo2.Setup<Task<List<int>>>(x => x.GetCampaignsOnRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => new List<int> { 1, 2 });
        mockCampaignRunningStatusRepo2.Setup(x => x.ConvertRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<RunningStatus>(), It.IsAny<Application>())).ThrowsAsync(new Exception());
        await Assert.ThrowsAsync<Exception>(() => sut.SetRunningStatusActive(data.Params.currentStatus, data.Params.updatedStatus, data.Params.application));
    }
    #endregion   
}
  • Random breaking snapshot

在此处输入图像描述

在此处输入图像描述

Help me to get the insights what I am doing wrong here?

AutoMoqData and ClassData will each generate their own test cases, they cannot be combined.

You are getting the error System.InvalidOperationException: The test method expected 3 parameter values, but 1 parameter value was provided. because you are providing a single parameter in your TheoryData class.

The support for class data is planned for v5 of AutoFixture.

Solved my problem using below steps -

Created ClassAutoMoqDataAttribute on top of AutoMoq that can adopt signature pattern.

public class ClassAutoMoqDataAttribute : CompositeDataAttribute
    {
        public ClassAutoMoqDataAttribute(Type values)
            : base(new ClassDataAttribute(values), new AutoMoqDataAttribute())
        {
        }
    }

Then Updated Test Case accordingly

public class SetRunningStatusActiveTestCase
{
    #region Theories
[Theory]
[ClassAutoMoqData(typeof(ValidValueTests))]
        public async Task ConvertRunningStatusTest_WhenValidCampaignExist_ReturnsTrue(ExpectedValueTestData<bool> data, [Frozen] Mock<ICampaignRunningStatusRepo> campaignRunningStatusRepoMock, CampaignRunningJob sut)
        {
            campaignRunningStatusRepoMock.Setup(x => x.GetCampaignsOnRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => new List<int> { 1, 2, 3 }).Verifiable();
        campaignRunningStatusRepoMock.Setup(x => x.ConvertRunningStatus(It.IsAny<RunningStatus>(), It.IsAny<RunningStatus>(), It.IsAny<Application>())).ReturnsAsync(() => 3);

        var actual = await sut.SetRunningStatusActive(data.Params.currentStatus, data.Params.updatedStatus, data.Params.application);
        Assert.Equal(data.ExpectedValue, actual);
        campaignRunningStatusRepoMock.Verify();
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM