ASP.NET 样板,具有真实数据库的测试用例

ASP.NET Boilerplate, test cases with real databases

我正在为 ASP.NET 5.x 的项目使用 asp.net 样板。我正在尝试为这个项目创建测试用例,它将调用现有的测试数据库(一个数据库用于主机,另一个数据库用于租户)。到目前为止我的步骤是:

  1. TestBase class 构造函数中,我正在调用一个与 MultiTenantMigrateExecuter.Run() 相同的方法,它将为测试主机数据库和测试租户数据库播种数据(我将使用主机数据库和单个租户数据库进行测试)。播种将与真实数据库相同,只是测试数据库的名称不同。
  2. 我还从 TestBase class 构造函数中获取主机数据库中的 TenantId。
  3. 接下来我尝试从租户数据库中获取任何种子用户 像这样: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 });
        }
    }
}

创建后,您可以在测试用例中使用它。