Base solution for your next web application
Open Closed

Test With Custom AppSession and Claims data #8171


User avatar
0
nicolaslau created

I add some addtional data to user claims using UserClaimsPrincipalFactory and using the data to do datafilter. the data can accessed through MyCustomAppSession

After this, i will write unit(integrated) test to test some method using datafilter.

My Question:

  1. how to set the data of MyCustomAppSession lika other testcase "AbpSession.Id=xxx"?
  2. how to set claim data that can be accessed by DbContext(for datafilter) in testcase?
  3. how to disable datafilter in testcase?

Thanks.


13 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    hi nicolaslau

    Please share the code of your MyCustomAppSession class and custom data filter.

  • User Avatar
    0
    nicolaslau created

    @maliming

    MyAppSession.cs

        public class MyAppSession: ClaimsAbpSession, ITransientDependency, IAppSession
        {
            public MyAppSession(
                IPrincipalAccessor principalAccessor,
                IMultiTenancyConfig multiTenancy,
                ITenantResolver tenantResolver,
                IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider
                ) :
            base(principalAccessor, multiTenancy, tenantResolver, sessionOverrideScopeProvider)
            {
    
            }
    
            public string LegacyTenantCode
            {
                get
                {
                    var legacyTenantCodeClaim = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type ==   MyClaimTypes.LegacyTenantCode);
                    var claimValue = legacyTenantCodeClaim?.Value;
                    return !string.IsNullOrEmpty(claimValue) ? claimValue : null;
                }
            }
    
        }
    

    MyDbContext

    protected virtual bool IsLegacyTenantCodeFilterEnabled => 
                CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled(MyDataFilters.MayHaveTenantCode ) == true;
    
            protected virtual string CurrentTenantCode => GetCurrentTenantCode();
    
            private string GetCurrentTenantCode()
            {
                var legacyTenantCodeClaim = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == JungleParkClaimTypes.LegacyTenantCode);
                var claimValue = legacyTenantCodeClaim?.Value;
                return !string.IsNullOrEmpty(claimValue) ? claimValue : null;
            }
    
            protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
            {
                if (typeof(IMayHaveLegacyTenantCode).IsAssignableFrom(typeof(TEntity)))
                {
                    return true;
                }
    
                return base.ShouldFilterEntity<TEntity>(entityType);
            }
    
            protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
            {
                var expression = base.CreateFilterExpression<TEntity>();
    
                if (typeof(IMayHaveLegacyTenantCode).IsAssignableFrom(typeof(TEntity)))
                {
                    Expression<Func<TEntity, bool>> mayHaveLegacyTenantCodeFilter = e => ((IMayHaveLegacyTenantCode)e).TenantCode == CurrentTenantCode || (((IMayHaveLegacyTenantCode)e).TenantCode == CurrentTenantCode) == IsLegacyTenantCodeFilterEnabled;
                    expression = expression == null ? mayHaveLegacyTenantCodeFilter : CombineExpressions(expression, mayHaveLegacyTenantCodeFilter);
                }
    
                return expression;
            }
    
  • User Avatar
    0
    nicolaslau created

    @maliming

    UserClaimsPrincipalFactory.cs (modified)

      public override async Task<ClaimsPrincipal> CreateAsync(User user)
            {
                var claim = await base.CreateAsync(user);
    
                if (user.TenantId.HasValue)
                {
                    //find legacy user
                    var legacyTenant = await _sysTenantManager.FindById((int)user.TenantId);
    
                    if (legacyTenant != null)
                    {
                        claim.Identities.First().AddClaim(new Claim(MyClaimTypes.LegacyTenantCode, legacyTenant.TenantCode));
                    }
                }
    
                return claim;
            }
    
  • User Avatar
    0
    maliming created
    Support Team

    hi

    You should inject and use MyAppSession in the GetCurrentTenantCode method.

    how to set the data of MyCustomAppSession lika other testcase "AbpSession.Id=xxx"? how to set claim data that can be accessed by DbContext(for datafilter) in testcase?

    You can use Substitute to mock MyAppSession.

    eg:

    // Mock session
    var session = Substitute.For <MyAppSession> ();
    session.LegacyTenantCode.Returns ("test");
    LocalIocManager.IocContainer.Register (Component.For <MyAppSession> (). Instance (session));
    

    how to disable datafilter in testcase?

    see https://aspnetboilerplate.com/Pages/Documents/Data-Filters#disable-filters https://aspnetboilerplate.com/Pages/Documents/Articles\How-To\add-custom-data-filter-ef-core#disable-filter

  • User Avatar
    0
    nicolaslau created

    For DataFilter, it uses DbContexts GetCurrentTenantCode method. Not using MyAppSessions GetCurrentTenantCode method.

  • User Avatar
    0
    maliming created
    Support Team

    hi

    I mean you should inject the MyAppSessions service in MyDbContext and then use MyAppSessions.LegacyTenantCode in the GetCurrentTenantCode method instead of getting LegacyTenantCode from PrincipalAccessor.Principal

  • User Avatar
    0
    nicolaslau created

    @maliming

    I do it now.

    my mock code is at testcase's arrange part. but it also call MyAppSession's LegacyTenantCode (i have setted it virtual ) not from NSustitute.

    where is the right place for the mock code

  • User Avatar
    0
    maliming created
    Support Team

    hi @nicolaslau

    my mock code is at testcase's arrange part.

    Please share your code.

  • User Avatar
    0
    nicolaslau created
                var session = Substitute.For<MyAppSession>(
                Resolve<IPrincipalAccessor>(),
                Resolve<IMultiTenancyConfig>(),
                Resolve<ITenantResolver>(),
                Resolve<IAmbientScopeProvider<SessionOverride>>()
                );
                session.LegacyTenantCode.Returns("425599f0-8383-41e6-bcb6-7710f5c29e8b");
                LocalIocManager.IocContainer.Register(Component.For<IAppSession>().Instance(session));
                
                //this method will trigger datafilter automatically
                 var output = await MyAppService.GetProjects(
                  new GetProjectsInput
                  {
                      MaxResultCount = 2,
                      Sorting = "DesignCode"
                  });
    
                //Assert
                output.TotalCount.ShouldBe(4);
                output.Items.Count.ShouldBe(2);
    
  • User Avatar
    0
    maliming created
    Support Team

    hi

    This is my test code, you can directly use the interface to facilitate mock services.

  • User Avatar
    0
    nicolaslau created

    @maliming Thanks. You code works. Mock session in TestBaseModule with LifestyleSingleton.

    But the next problem is i want different value for each testcase. how to do it ???

  • User Avatar
    0
    maliming created
    Support Team

    Try Named(Guid.NewGuid().ToString()).IsDefault()

    [Fact]
    public async Task Test1()
    {
    	var session = Substitute.For<IAppSession>();
    	session.LegacyTenantCode.Returns("xxxx");
    	LocalIocManager.IocContainer.Register(Component.For<IAppSession>().Instance(session).LifestyleSingleton().Named(Guid.NewGuid().ToString())
    		.IsDefault());
    
    	var sessionAppService = Resolve<ISessionAppService>();
    
    	//Act
    	var output = await sessionAppService.GetCurrentLoginInformations();
    }
    
    [Fact]
    public async Task Test2()
    {
    	var session = Substitute.For<IAppSession>();
    	session.LegacyTenantCode.Returns("yyy");
    	LocalIocManager.IocContainer.Register(Component.For<IAppSession>().Instance(session).LifestyleSingleton().Named(Guid.NewGuid().ToString())
    		.IsDefault());
    
    	var sessionAppService = Resolve<ISessionAppService>();
    
    	//Act
    	var output = await sessionAppService.GetCurrentLoginInformations();
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    This issue is closed because it has not had recent activity for a long time.