ASP.NET 样板,具有真实数据库的测试用例
ASP.NET Boilerplate, test cases with real databases
我正在为 ASP.NET 5.x 的项目使用 asp.net 样板。我正在尝试为这个项目创建测试用例,它将调用现有的测试数据库(一个数据库用于主机,另一个数据库用于租户)。到目前为止我的步骤是:
- 在
TestBase
class 构造函数中,我正在调用一个与 MultiTenantMigrateExecuter.Run()
相同的方法,它将为测试主机数据库和测试租户数据库播种数据(我将使用主机数据库和单个租户数据库进行测试)。播种将与真实数据库相同,只是测试数据库的名称不同。
- 我还从
TestBase
class 构造函数中获取主机数据库中的 TenantId。
- 接下来我尝试从租户数据库中获取任何种子用户
像这样:
var user= UsingDbContext(context => context.Users.FirstOrDefault(t => t.UserName== "johndoe"));
但当然这将调用 HostDb 而不是 TenantDb。
我找到了一种通过将代码包装在这样的 using 语句中来调用 TenantDb 的方法,避免使用 context
和使用存储库,以便能够从租户数据库:
using (this.AbpSession.Use(tenant.Id, null))
{
// get the TenantDb.User here by using the User repository
}
...然后在我写的每个测试用例中都这样:
using (this.AbpSession.Use(AbpSession.TenantId, AbpSession.UserId))
{
// make calls to the Tenant database here by using Tenant repository
}
但这不是最干净的解决方案,它有其局限性。
问题是:在我的情况下是否有更好的方法,在 TestBase
class 上下文中设置默认调用租户数据库而不是主机数据库?
这个我也试过了,但是不行...
protected T UsingTenantDbContext<T>(Func<TestAppDbContext, T> func)
{
T result;
using (this.AbpSession.Use(AbpSession.TenantId, AbpSession.UserId))
{
using (var context = LocalIocManager.Resolve<TestAppDbContext>())
{
context.DisableAllFilters();
result = func(context);
context.SaveChanges();
}
}
return result;
}
玩了一会儿代码后,我找到了问题的答案...
在 TestBase class 我创建了一个新的静态 属性:
internal static MyAppDbContext tenantContext;
静态的,因为这个class会被多次继承,但是tenantContext应该只设置一次。
接下来我创建了以下方法:
protected void CreateTenantDbContext()
{
if (tenantContext == null)
{
using (var context = LocalIocManager.Resolve<MyAppDbContext>())
{
// AbpSession.TenantId is set in a previous method.
// Usin the host context, get the Connection String for the necessary tenant
var encryptedDbConnString = context.Tenants.FirstOrDefault(x => x.Id == AbpSession.TenantId)?.ConnectionString;
// Decrypt the string
var decryptedDbConnString = SimpleStringCipher.Instance.Decrypt(encryptedDbConnString);
// Create the context for the tenant db and assign it to the static property tenantContext
tenantContext = LocalIocManager.Resolve<MyAppDbContext>(new { nameOrConnectionString = decryptedDbConnString });
}
}
}
创建后,您可以在测试用例中使用它。
我正在为 ASP.NET 5.x 的项目使用 asp.net 样板。我正在尝试为这个项目创建测试用例,它将调用现有的测试数据库(一个数据库用于主机,另一个数据库用于租户)。到目前为止我的步骤是:
- 在
TestBase
class 构造函数中,我正在调用一个与MultiTenantMigrateExecuter.Run()
相同的方法,它将为测试主机数据库和测试租户数据库播种数据(我将使用主机数据库和单个租户数据库进行测试)。播种将与真实数据库相同,只是测试数据库的名称不同。 - 我还从
TestBase
class 构造函数中获取主机数据库中的 TenantId。 - 接下来我尝试从租户数据库中获取任何种子用户
像这样:
var user= UsingDbContext(context => context.Users.FirstOrDefault(t => t.UserName== "johndoe"));
但当然这将调用 HostDb 而不是 TenantDb。
我找到了一种通过将代码包装在这样的 using 语句中来调用 TenantDb 的方法,避免使用 context
和使用存储库,以便能够从租户数据库:
using (this.AbpSession.Use(tenant.Id, null))
{
// get the TenantDb.User here by using the User repository
}
...然后在我写的每个测试用例中都这样:
using (this.AbpSession.Use(AbpSession.TenantId, AbpSession.UserId))
{
// make calls to the Tenant database here by using Tenant repository
}
但这不是最干净的解决方案,它有其局限性。
问题是:在我的情况下是否有更好的方法,在 TestBase
class 上下文中设置默认调用租户数据库而不是主机数据库?
这个我也试过了,但是不行...
protected T UsingTenantDbContext<T>(Func<TestAppDbContext, T> func)
{
T result;
using (this.AbpSession.Use(AbpSession.TenantId, AbpSession.UserId))
{
using (var context = LocalIocManager.Resolve<TestAppDbContext>())
{
context.DisableAllFilters();
result = func(context);
context.SaveChanges();
}
}
return result;
}
玩了一会儿代码后,我找到了问题的答案... 在 TestBase class 我创建了一个新的静态 属性:
internal static MyAppDbContext tenantContext;
静态的,因为这个class会被多次继承,但是tenantContext应该只设置一次。
接下来我创建了以下方法:
protected void CreateTenantDbContext()
{
if (tenantContext == null)
{
using (var context = LocalIocManager.Resolve<MyAppDbContext>())
{
// AbpSession.TenantId is set in a previous method.
// Usin the host context, get the Connection String for the necessary tenant
var encryptedDbConnString = context.Tenants.FirstOrDefault(x => x.Id == AbpSession.TenantId)?.ConnectionString;
// Decrypt the string
var decryptedDbConnString = SimpleStringCipher.Instance.Decrypt(encryptedDbConnString);
// Create the context for the tenant db and assign it to the static property tenantContext
tenantContext = LocalIocManager.Resolve<MyAppDbContext>(new { nameOrConnectionString = decryptedDbConnString });
}
}
}
创建后,您可以在测试用例中使用它。