Finbuckle / Finbuckle.MultiTenant

Finbuckle.MultiTenant is an open-source multitenancy middleware library for .NET. It enables tenant resolution, per-tenant app behavior, and per-tenant data isolation.
https://www.finbuckle.com/multitenant
Apache License 2.0
1.31k stars 267 forks source link

Mocking StoreInfo? #800

Closed charlieH1 closed 6 months ago

charlieH1 commented 6 months ago

Hi Guys

Writing some unit tests for some stuff and I need to fake the store (I'm using nSubstitute and no we cant use Moq after the recent shenanigans over there) I was wondering if theres a way I can get the storeInfo but as a interface currently IMutlTenantContext provides it as a class so I cant mock it. I'm going down the route currently of injecting IMultiTenantContextAccessor using the DI and then navigating through MultiTenantContext to StoreInfo. Is thre a different and or better way which will allow me to mock or am scuppered and stuck with what I have. Below is a code snippet of what I'm trying to do and its the line that returnsnull that NSubstitute is unable to act on.

var mockGeneralHelper = Substitute.For<IGeneralHelper>();
var mockContextAccessor = Substitute.For<IMultiTenantContextAccessor<BasicTenantInfo>>();
var mockTenantContext = Substitute.For<IMultiTenantContext<BasicTenantInfo>>();
var mockStoreInfo = Substitute.For<StoreInfo<BasicTenantInfo>>();
var mockLogger = Substitute.For<MockLogger<TenantManagementController>>();
mockTenantContext.HasResolvedTenant.Returns(true);
mockStoreInfo.Store.ReturnsNull();
mockTenantContext.StoreInfo.Returns(mockStoreInfo);
mockContextAccessor.MultiTenantContext.Returns(mockTenantContext);
var sut = new TenantManagementController(mockContextAccessor, mockGeneralHelper, mockLogger);
charlieH1 commented 6 months ago

I did some further digging and think I might have the solution myself but please correct me if wrong or there is a better one

I can fetch the store (which is the endgame of the code anyway) by using the DI which is done by the following steps when using an Ef store:

  1. the withEfCoreStore calls here
  2. which calls here and adds it to the DI

so now in my code I will call something like:

 public TenantManagementController(IMultiTenantContextAccessor<BasicTenantInfo> multiTenantContextAccessor, IMultiTenantStore<BasicTenantInfo> tenantStore,IGeneralHelper generalHelper, ILogger<TenantManagementController> logger) {
     _generalHelper = generalHelper;
     _contextAccessor = multiTenantContextAccessor;
     _tenantStore = tenantStore;
     _logger = logger;
 }
AndrewTriesToCode commented 6 months ago

Looks like a solid approach to me. Cheers.