6

Ich bin derzeit in dem Prozess Unit-Tests für die Entity Framework 6 Operationen in API meiner ASP.NET Web 2.0-Anwendung hinzuzufügen, mit den folgenden MSDN-Tutorial:Unit-Tests Entity Framework 6 mit IdentityDbContext

http://msdn.microsoft.com/en-us/data/dn314431

Das Lernprogramm schlägt vor, eine Schnittstelle zu erstellen, die anstelle der DbContext-Klasse der Anwendung verwendet wird. Diese Schnittstelle wird dann in der gesamten Anwendung verwendet, so dass die Controller mit einem "verspotteten" Testkontext getestet werden können.

Im Folgenden ist die vorgeschlagene Schnittstelle aus dem Tutorial:

public interface IApplicationDbContext : IDisposable 
{ 
    DbSet<Blog> Blogs { get; } 
    DbSet<Post> Posts { get; } 
    Task<int> SaveChangesAsync(); 
} 

Leider ist dieses Tutorial geht davon aus:

public interface IBloggingContext 
{ 
    DbSet<Blog> Blogs { get; } 
    DbSet<Post> Posts { get; } 
    int SaveChanges(); 
} 

Wie verwende ich SaveChangesAsync() statt, ich die Schnittstelle zu dem unten geändert haben dass der Kontext eine Basisklasse von DbContext hat, wenn meins IdentityDbContext als Basisklasse verwendet (siehe unten). Es scheint keine Möglichkeit zu geben, SaveChangesAsync() - die ich anstelle von SaveChanges() verwende - aus meinem Kontext aufzurufen, so dass die Schnittstelle nicht korrekt implementiert werden kann.

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext 
{ 
    public ApplicationDbContext() 
     : base("DefaultConnection", throwIfV1Schema: false) 
    { 

    } 

    public Task<int> SaveChangesAsync() 
    { 
     // No way to call DbContext.SaveChangesAsync() from here 
    } 
} 

Alle Ideen oder Vorschläge würden sehr geschätzt werden!

EDIT:

Im Folgenden sind Kopien der Klassen, die derzeit im Einsatz sind:

ApplicationDbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext 
{ 
    public ApplicationDbContext() 
     : base("DefaultConnection", throwIfV1Schema: false) 
    { 

    } 

    public Task<int> SaveChangesAsync() 
    { 
     // Cannot resolve base.SaveChangesAsync() from here 
    } 

    public DbSet<Product> Products { get; set; } 
} 

IApplicationDbContext

public interface IApplicationDbContext 
{ 
    Task<int> SaveChangesAsync(); 
    DbSet<Product> Products { get; set; } 
} 

Beispiel Controller-Constructor (die die Schnittstelle verwendet)

protected BaseEntityController(IApplicationDbContext context) 
{ 
    db = context; 
} 

EDIT 2:

Es scheint, dass es könnte ein Problem mit der Klassenhierarchie sein. Im Folgenden eine andere ist (hoffentlich ähnliche) Fehler bauen:

UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db)); 

Error 2 Argument 1: cannot convert from 'IApplicationDbContext' to 'System.Data.Entity.DbContext' 

Als Referenz hat meine ApplicationUser Klasse eine Basisklasse von IdentityUser:

public class ApplicationUser : IdentityUser 

EDIT 3:

Wie Jon erwähnt , der in EDIT 2 gepostete Fehler ist zu erwarten. Leider ist der Fehler auch für den Kontext selbst (ApplicationDbContext) und nicht nur für die Schnittstelle (IApplicationDbContext) aufgetreten.

Das Problem wurde behoben, sondern nur durch eine Deinstallation und die Pakete aus der Lösung der Neuinstallation von Visual Studio neu starten und dann das Projekt neu zu erstellen. Ich bin mir immer noch nicht sicher über die genaue Ursache des Problems.

Ich habe Jon Antwort als richtig markiert, da es unter normalen Umständen wäre.

Antwort

8

Nach MSDN hereIdentityDbContext erbt von DbContext., Wenn Sie also direkt anrufen müssen dann base.SaveChangesAsync sollte funktionieren.

Sie müssen diese Methode jedoch nicht implementieren, da sie bereits im Realkontext von DbContext implementiert wurde, es sei denn, Sie verwenden eine explizite Schnittstellenimplementierung oder fügen mehr Code hinzu (auf den Sie nicht zugreifen) Beispiel). Sie müssen im TestDbContext etwas implementieren, da es nicht von DbContext geerbt wird.

Wenn ich SaveChangesAsync implementieren, wie Sie aussehen:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext 
{ 
    public Task<int> SaveChangesAsync() 
    { 
     return base.SaveChangesAsync(); 

     // No way to call DbContext.SaveChangesAsync() from here 
    } 
} 

Dann auf Build bekomme ich diese Warnung:

Warning 1 'SOWorking.ApplicationDbContext.SaveChangesAsync()' hides inherited member 'System.Data.Entity.DbContext.SaveChangesAsync()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

Der Build hat keine Warnungen, wenn ich entweder die Umsetzung von SaveChangesAsync auslassen ganz

public override Task<int> SaveChangesAsync() 
{ 
    return base.SaveChangesAsync(); 
} 

Allerdings, wenn Sie: oder Überschreibung wie folgt hinzufügen Haben Sie sonst noch etwas zu tun in SaveChangesAsync dann ist das sinnlos (und Resharper graut es für Sie als solche).

+0

Vielen Dank für Ihre ausführliche Antwort! Leider 'return base.SaveChangesAsync();' bewirkt, dass der Build fehlschlägt, da .SaveChangesAsync() nicht aufgelöst werden kann. –

+0

Ich kann das nicht reproduzieren. Ist das in Ihrem 'ApplicationDbContext' oder im' TestContext'? –

+0

Die 'ApplicationDbContext' –