2017-07-03 3 views
0

Ich benutze asp.net boilerplate für ein Projekt für ASP.NET 5.x. Ich versuche, Testfälle für dieses Projekt zu erstellen, das vorhandene Testdatenbanken aufruft (eine Datenbank für Host und die andere DB für Tenant). Meine Schritte waren so weit:ASP.NET Boilerplate, Testfälle mit echten Datenbanken

  1. In TestBase Klassenkonstruktors ich eine Methode nenne, die die gleiche wie MultiTenantMigrateExecuter.Run() arbeiten, welche die Daten für den Test-Host-Datenbank Seed wird und der Test-Tenant-Datenbank (Ich werde die unter Verwendung von Host db und eine einzige Tenant db zum Testen). Das Seeding wird dasselbe sein wie für die reale db, nur mit verschiedenen Namen für die Test-DBs.
  2. Auch aus dem Klassenkonstruktor TestBase bekomme ich die TenantId von der Host-Datenbank.
  3. Als nächstes versuche ich, jeden gesetzten Benutzer aus der Mieter-Datenbank wie folgt zu bekommen: var user= UsingDbContext(context => context.Users.FirstOrDefault(t => t.UserName== "johndoe"));, aber natürlich wird dies die HostDb nicht die TenantDb aufrufen.

fand ich einen Weg, um einen Anruf zu dem TenantDb zu machen, indem Sie den Code in einer using-Anweisung wie diese Umhüllung, die context avoidint und das Repository USInt, in der Lage sein den Benutzer ich vom TenantDb müssen erhalten:

using (this.AbpSession.Use(tenant.Id, null)) 
{ 
    // get the TenantDb.User here by using the User repository 
} 

... und dann so in jedem Testfall ich schreiben:

using (this.AbpSession.Use(AbpSession.TenantId, AbpSession.UserId)) 
{ 
    // make calls to the Tenant database here by using Tenant repository 
} 

aber dies ist nicht die saubere Lösung, und es hat seine Grenzen. Die Frage ist: Gibt es einen besseren Weg in meinem Fall, in der TestBase Klasse den Kontext zu setzen, um Anrufe an die Tenant-Datenbank standardmäßig anstelle der Host-Datenbank zu machen?

Ich habe versucht, diese auch, aber es funktioniert nicht ...

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; 
} 

Antwort

0

Nach einer Weile mit dem Code zu spielen, fand ich die Antwort auf meine Frage ... In der Testbase-Klasse I habe eine neue statische Eigenschaft erstellt:

internal static MyAppDbContext tenantContext; 

Static, weil diese Klasse mehrere Male vererbt werden, aber die tenantContext sollte nur einmal eingestellt werden.

Als nächstes habe ich die folgende Methode erstellt:

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 }); 
     } 
    } 
} 

Einmal erstellt Sie es in Ihrem Testfälle verwenden können.

Verwandte Themen