Home > Back-end >  How to Automoq concrete class dependencies through Automoq?
How to Automoq concrete class dependencies through Automoq?

Time:01-07

In my class constrctur, we had multiple concrete class dependencies. as per automoq documentation, we can only interface or abstraction.

System Under Test Class, in that ManageLocationRepository is concrete class dependency.

public class CityEventListener : IEvent<LocationChangeEventData>
    {
        private readonly ILocationAdapterCaller _locationAdapterCaller;
        private readonly ManageLocationRepository _managerLocationRepository;

        public CityEventListener(ILocationAdapterCaller locationAdapterCaller, ManageLocationRepository managerLocationRepository)
        {
            _locationAdapterCaller = locationAdapterCaller;
            _managerLocationRepository = managerLocationRepository;
        }

        public async Task<bool> ProcessEvent(LocationChangeEventData eventData)
        {
        }
    }

Test Case -

[Theory(DisplayName = "Valid value test")]
        [ClassAutoMoqData(typeof(ValidValueTests))]
        public async Task ProcessEvent_WithCreateOrUpdateOperation_CallsUpsertCityAndReturnsResult(ExpectedValueTestData<Parameters, bool> data,
        [Frozen] Mock<ILocationAdapterCaller> locationAdapterCallerMock, [Frozen] Mock<ManageLocationRepository> managerLocationRepositoryMock,
        CityEventListener sut)
        {
            // fakes
            var cityDetail = _fixture.Build<CityDetail>()
                                    .With(x => x.Id, data.Params.locationChangeEventData.Id).Create();

            // Arrange
            locationAdapterCallerMock.Setup(mock => mock.GetCityDetail(data.Params.locationChangeEventData.Id))
                .ReturnsAsync(cityDetail).Verifiable();

            managerLocationRepositoryMock
                .Setup(mock => mock.UpsertCity(cityDetail))
                .ReturnsAsync(data.ExpectedValue).Verifiable();

            var result = await sut.ProcessEvent(data.Params.locationChangeEventData);

            // Assert
            using (new AssertionScope())
            {
                Assert.IsType<bool>(result);
                Assert.Equal(data.ExpectedValue, result);
                locationAdapterCallerMock.Verify();
                managerLocationRepositoryMock.Verify();
            }
        }

ClassAutoMoq Attribute

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

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute() : base(() =>
    {
        var fixture = new Fixture().Customize(new CompositeCustomization(
            new AutoMoqCustomization() { ConfigureMembers = true, GenerateDelegates = true },
            new SupportMutableValueTypesCustomization()));

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

        return fixture;
    })
    {
    }
}

what are the alternate way to moq such dependencies through automoq attribute.

CodePudding user response:

I solved my problem by taking two actions -

  1. mark concrete class method virtual
  2. create custome class automoq attribute to freeze dependencies
public class CityEventListenerClassAutoMoqAttribute : CompositeDataAttribute
   {
       public CityEventListenerClassAutoMoqAttribute(Type values)
           : base(new ClassDataAttribute(values), new CityEventListenerAutoMoqAttribute())
       {
       }
   }

   public class CityEventListenerAutoMoqAttribute : AutoDataAttribute
   {
       public CityEventListenerAutoMoqAttribute()
           : base(() =>
   {
       var fixture = new Fixture().Customize(new CompositeCustomization(
           new AutoMoqCustomization() { ConfigureMembers = true, GenerateDelegates = true },
           new SupportMutableValueTypesCustomization()));
       var managerLocationRepositoryMock =
               fixture.Freeze<Mock<ManageLocationRepository>>();
       fixture.Inject(managerLocationRepositoryMock.Object);
       return fixture;
   })
       {
       }
   }

Now my test case looks like this -

[Theory(DisplayName = "Valid value test")]
        [CityEventListenerClassAutoMoq(typeof(ValidValueTests))]
        public async Task ProcessEvent_WithCreateOrUpdateOperation_CallsUpsertCityAndReturnsResult(ExpectedValueTestData<Parameters, bool> data,
        [Frozen] Mock<ILocationAdapterCaller> locationAdapterCallerMock, [Frozen] Mock<ManageLocationRepository> managerLocationRepositoryMock,
        CityEventListener sut)
        {
            // fakes
            var cityDetail = _fixture.Build<CityDetail>()
                                    .With(x => x.Id, data.Params.locationChangeEventData.Id).Create();

            // Arrange
            locationAdapterCallerMock.Setup(mock => mock.GetCityDetail(data.Params.locationChangeEventData.Id))
                .ReturnsAsync(cityDetail).Verifiable();

            managerLocationRepositoryMock
                .Setup(mock => mock.UpsertCity(cityDetail))
                .ReturnsAsync(data.ExpectedValue).Verifiable();

            var result = await sut.ProcessEvent(data.Params.locationChangeEventData);

            // Assert
            using (new AssertionScope())
            {
                Assert.IsType<bool>(result);
                Assert.Equal(data.ExpectedValue, result);
                locationAdapterCallerMock.Verify();
                managerLocationRepositoryMock.Verify();
            }
        }

Do let me know if I can improve anything in my approach.

  • Related