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:
- 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?
- how to disable datafilter in testcase?
Thanks.
13 Answer(s)
-
0
hi nicolaslau
Please share the code of your MyCustomAppSession class and custom data filter.
-
0
@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; }
-
0
@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; }
-
0
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
-
0
For DataFilter, it uses DbContext
s GetCurrentTenantCode method. Not using MyAppSession
s GetCurrentTenantCode method. -
0
hi
I mean you should inject the
MyAppSessions
service inMyDbContext
and then useMyAppSessions.LegacyTenantCode
in theGetCurrentTenantCode
method instead of gettingLegacyTenantCode
fromPrincipalAccessor.Principal
-
0
@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
-
0
hi @nicolaslau
my mock code is at testcase's arrange part.
Please share your code.
-
0
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);
-
0
-
0
@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 ???
-
0
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(); }
-
0
This issue is closed because it has not had recent activity for a long time.