Open Closed

UnitTesting of Overridden methods of IdentiyAppServices like IdentityUserAppService, IdentityRoleAppService etc. etc. #1298


User avatar
0
lalitChougule created
  • ABP Framework version: v3.0.4
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no / yes
  • Exception message and stack trace: N.A
  • Steps to reproduce the issue: N.A

Hi,

I have do some code change in IdentityUserAppService, IdentityRoleAppService and ProfileAppService by overridding few methods. Now I want to do Unit Testing of the overridden methods, How do I do it ? Difficulty facing while writing Unit Testing :

  1. While overridding I haven't created any Interface for my OverriddenAppService class, So in constructor if I user this code block _userAppService = GetRequiredService<IIdentityUserAppService>(); this means I am refering to IIdentityUserAppService Methods not my overridden methods right ?
  2. I have created few custom stuff i.e. if my role say some AnchorAdmin roles logges in user can see only user with same Roles etc. etc. The main problem is how do I seed my testing db with the user details I am playing around with, and then how do I log in with different users to fetch customized data.

In short In my code block I have to fake my login with a particular user as my method have this kind code : For example as below :

public virtual async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
{
    var user = new IdentityUser(
            GuidGenerator.Create(),
            input.UserName,
            input.Email,
            CurrentTenant.Id
        );

    if (logged in with user : xyz@abc.com) //then only I have to map extra properties other wise I dont have to map it
    {
         input.MapExtraPropertiesTo(user);
    }

    (await UserManager.CreateAsync(user, input.Password)).CheckErrors();
    await UpdateUserByInput(user, input);

    await CurrentUnitOfWork.SaveChangesAsync();

    return ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
}

So in order to test this kind of code I have to create a session where my xyz@abc.com user is logged in, then and then only I can check my code block right ?

Please help !!!


8 Answer(s)
  • User Avatar
    0
    cotur created

    Hi @lalitChougule

    The class XAppService is just an implementation of interface IXAppService, so when you override the implementation (class) you should also replace the implementation of interface IXAppService to your OverriddenAppService. Please see this documentation.

    When you resolve IXAppService, the Dependency Injection should use OverridenAppService instead of default implementation.

    After that, there is no problem to use GetRequiredService<IIdentityUserAppService>(); in tests and everywhere.

  • User Avatar
    0
    lalitChougule created

    Hi @cotur,

    I will try that. Please provide me solution for my second point as well.

    User cases :

    I have 2 users (user_1 and user_2), when I log with user_1 and create another user I check if my user is created by user_1 then I have some different action/code to be executed, and if my user_2 login I have to perform different action/code.This is just an example, but I hope u got my point.

    Basic Requirement in Unit Test

    I need to know how to I write test case where my user_1 is logged in and where my user_2 is logged in. And how do I seed IdentityUser i.e. AbpUsers table in test env with user_1 and user_2 details because as what I have learned there are more than one tables are involved as below:

    1. AbpUsers
    2. AbpUserRoles
    3. AbpRoles

    etc etc How to I seed the above tables with my data.

    Thanks

  • User Avatar
    0
    cotur created

    There should be FakeCurrentPrincipalAccessor.cs file in your TestBase project, we use it to mock user.

    Also for data seeding, please check this documentation: https://docs.abp.io/en/abp/latest/Testing#the-seed-data

  • User Avatar
    0
    lalitChougule created

    There should be FakeCurrentPrincipalAccessor.cs file in your TestBase project, we use it to mock user.

    Also for data seeding, please check this documentation: https://docs.abp.io/en/abp/latest/Testing#the-seed-data

    I got it GetPrincipal() method, but it has main admin. How do I use it in my case. I need to create more than 3-4 Unit test where each method have different login user with different case.

    [Fact]
    public async CheckForUser_1()
    {
        using(user_1 logged in)
        {
            //my code
        }
    }
    
    [Fact]
    public async CheckForUser_2()
    {
        using(user_2 logged in)
        {
            //my code
        }
    }
    
    [Fact]
    public async CheckForUser_3()
    {
        using(user_3 logged in)
        {
            //my code
        }
    }
    
    [Fact]
    public async CheckForUser_4()
    {
        using(user_4 logged in)
        {
            //my code
        }
    }
    

    So where I have used using(user_1 logged in ) how can I use the method you mentioned ?

  • User Avatar
    0
    cotur created

    You can use ICurrentPrincipalAccessor service to change users.

    The FakeCurrentPrincipalAccessor that I mentioned before is also implements ICurrentPrincipalAccessor

    First, inject the ICurrentPrincipalAccessor in your test class

    public class MyTest : MyTestBase
    {
            private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
            
            public MyTest()
            {
                _currentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>();
            }
    }
    

    Then use Change method with using statement to set new user.

    [Fact]
    public async CheckForUser_4()
    {
        var user_4 = new ClaimsPrincipal();
        using (_currentPrincipalAccessor.Change(user_4))
        {
            // here, the current user will be user_4
        }
    }
    
  • User Avatar
    0
    lalitChougule created

    Hi cotur,

    I was partially achieve your solution. But I have hit a dead end while seeding Roles

    My Code :

     public class IdentityRolesDataSeedContributor : IDataSeedContributor, ITransientDependency
        {
            private readonly IRepository<IdentityRole> _identityRoleRepository;
    
            public IdentityRolesDataSeedContributor(IRepository<IdentityRole> identityRoleRepository)
            {
                _identityRoleRepository = identityRoleRepository;
            }
    
            public async Task SeedAsync(DataSeedContext context)
            {
                await _identityRoleRepository.InsertAsync(new IdentityRole(
                    id: Guid.Parse("60353FF7-0F81-4DD5-AC1F-6F9559037720"),
                    name: "RoleAbc",
                    tenantId: Guid.Parse("d1be844b-d3a2-031a-f036-39f5d4380239")));
            }
        }
    

    Error while unit testing :

    ---------- Starting test run ----------
    [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.4.2+2d84eb3141 (64-bit .NET Core 3.1.13)
    [xUnit.net 00:00:02.63]   Starting:    SCV.Litmus.Application.Tests
    [xUnit.net 00:00:15.39]     SCV.Litmus.LitmusIdentity.LitmusIdentityUserApplicationTests.CreateAsync [FAIL]
    [xUnit.net 00:00:15.39]       System.InvalidOperationException : Role ROLEABC does not exist!
    [xUnit.net 00:00:15.39]       Stack Trace:
    [xUnit.net 00:00:15.39]            at Volo.Abp.Identity.IdentityUserStore.AddToRoleAsync(IdentityUser user, String normalizedRoleName, CancellationToken cancellationToken)
    [xUnit.net 00:00:15.39]            at Microsoft.AspNetCore.Identity.UserManager`1.AddToRolesAsync(TUser user, IEnumerable`1 roles)
    [xUnit.net 00:00:15.39]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.39]            at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Identity.IdentityUserManager.SetRolesAsync(IdentityUser user, IEnumerable`1 roleNames)
    [xUnit.net 00:00:15.39]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.39]            at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.39]            at Volo.Abp.Identity.IdentityUserAppService.UpdateUserByInput(IdentityUser user, IdentityUserCreateOrUpdateDtoBase input)
    [xUnit.net 00:00:15.40]         D:\Litmus\Projects\ap-ar-dashboard\SCV.Litmus\aspnet-core\modules\litmus-core\src\SCV.Litmus.Application\LitmusIdentity\LitmusIdentityUserAppService.cs(106,0): at SCV.Litmus.LitmusIdentity.LitmusIdentityUserAppService.CreateAsync(IdentityUserCreateDto input)
    [xUnit.net 00:00:15.40]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.40]            at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.40]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.40]            at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.40]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.40]            at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.40]            at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
    [xUnit.net 00:00:15.40]            at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
    [xUnit.net 00:00:15.40]            at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
    [xUnit.net 00:00:15.40]         D:\Litmus\Projects\ap-ar-dashboard\SCV.Litmus\aspnet-core\modules\litmus-core\test\SCV.Litmus.Application.Tests\LitmusIdentity\LitmusIdentityUserApplicationTests.cs(89,0): at SCV.Litmus.LitmusIdentity.LitmusIdentityUserApplicationTests.CreateAsync()
    [xUnit.net 00:00:15.40]         --- End of stack trace from previous location where exception was thrown ---
    [xUnit.net 00:00:15.42]   Finished:    SCV.Litmus.Application.Tests
    ========== Test run finished: 1 Tests run in 17.2 sec (0 Passed, 1 Failed, 0 Skipped) ==========
    

    Can you tell me what I am doing wrong here ?

  • User Avatar
    0
    alper created
    Support Team Director

    Maybe that's case-sensitive.

    await _identityRoleRepository.InsertAsync(new IdentityRole( id: Guid.Parse("60353FF7-0F81-4DD5-AC1F-6F9559037720"), name: "RoleAbc", tenantId: Guid.Parse("d1be844b-d3a2-031a-f036-39f5d4380239")));


    System.InvalidOperationException : Role ROLEABC does not exist!

  • User Avatar
    0
    ServiceBot created
    Support Team Automatic process manager

    This question has been automatically marked as stale because it has not had recent activity.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11