Base solution for your next web application
Open Closed

How To Mock SettingManager for Unit Testing #3635


User avatar
0
carelearning created

Hey Volosoft,

Do you have a recommended method of using a test double for ISettingManger or SettingManger in a unit test?

I know I have to avoid the generic extension methods as they are not mockable.

So my production code looks like this (see unabridged as DateRangeInvalidAsync.png):

var setting = await _settingManager.GetSettingValueForApplicationAsync("DateRangeMaximum");
  Int32.TryParse(setting, out int yearLimit);

My unit test method has this code (see unabridged as EnrollmentAppServiceTests.png):

_settingManager.Setup(x => x.GetSettingValueForApplicationAsync("DateRangeMaximum"))
                .Returns(Task.FromResult("100"));

My test configuration consists of XUnit, Moq and Autofixture. The error I get is [https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp/Configuration/SettingDefinition.cs]) requires a parameterless constructor.

Regards,


4 Answer(s)
  • User Avatar
    0
    alper created
    Support Team

    Hi,

    In AbpZero Tests there's a similar implementation. In the class TenantRegistrationAppService_Tests, we mocked IPaymentCache. See the class for further information

    public class TenantRegistrationAppService_Tests : AppTestBase
        {
            private readonly ITenantRegistrationAppService _tenantRegistrationAppService;
            private readonly ISubscriptionPaymentRepository _subscriptionPaymentRepository;
    
            private IPaymentCache _fakePaymentCache;
            private readonly string samplePaymentId = Guid.NewGuid().ToString();
    
            public TenantRegistrationAppService_Tests()
            {
                RegisterFakePaymentCache();
                _tenantRegistrationAppService = Resolve<ITenantRegistrationAppService>();
                _subscriptionPaymentRepository = Resolve<ISubscriptionPaymentRepository>();
            }
    
            private void RegisterFakePaymentCache()
            {
                _fakePaymentCache = Substitute.For<IPaymentCache>();
                _fakePaymentCache.GetCacheItemOrNull(SubscriptionPaymentGatewayType.Paypal, samplePaymentId).Returns(new PaymentCacheItem(SubscriptionPaymentGatewayType.Paypal, PaymentPeriodType.Monthly, samplePaymentId));
                _fakePaymentCache.GetCacheItemOrNull(SubscriptionPaymentGatewayType.Paypal, samplePaymentId).Returns(new PaymentCacheItem(SubscriptionPaymentGatewayType.Paypal, PaymentPeriodType.Annual, samplePaymentId));
                LocalIocManager.IocContainer.Register(Component.For<IPaymentCache>().Instance(_fakePaymentCache).IsDefault());
            }
    ...
    }
    
  • User Avatar
    0
    carelearning created

    Dear @alper,

    Using the guidance from the Asp.Net core project.

    I tried just replacing the mocking container using NSubstitute from AutoFixture.AutoMoq as per the example, see below.

    // _settingManager = fixture.Freeze<Mock<ISettingManager>>();
       
        _settingManager = Substitute.For<ISettingManager>();
        fixture.Inject<ISettingManager>(_settingManager);
    

    I'm still getting the Parameterless constructor error in SettingDefinition (see SettingDefinition_Parameterless_Ctor.png).

    When we started a year plus ago with Apb Zero we created some custom database contexts. This is because of the great feature of Single Deployment with Multiple Databases which fits our needs exactly (see Custom_DbContexts.png).

    For better or worse we struggled using AppTestBase class and abandoned deriving from it for our custom tests.

    So I'm going to need to spend a little time to research reintegrating or creating a new base class to take advantage of LocalIocManager and Component from the aforementioned example you provided.

    Thanks for your expertise, effort and time.

  • User Avatar
    0
    carelearning created

    The issue has now been resolved.

    It was a stupid mistake while the test was mocking an ISettingManger. The production code was constructor injecting a SettingManager.

    Altering the production dependency to inject an ISettingManger resulted in the expected behavior.

    Thanks for your time.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Great :)