2017-05-20 1 views
0

Ich bin neu in Moq, und ich möchte Komponententests damit schreiben. Ich habe eine Datenbank mit ein paar Tischen, wie:C#/Moq - Wie wird mit mehrstufigen Testdaten gefüllt?

EducationUser | Application 
- UsrName   - Student 
- UsrPwd   - CourseId 
- UsrChallenge - Date 
- IsTeacher  - Grade 
- FullName 

Dies ist eine Datenbank auf einem localdb, die ich verspotten wollen. Ich habe die Entitäten mit dem Entity Framework erstellt. Die Schnittstelle dieser Entitäten ist IEducationEntities.

Nun würde Ich mag ein Mock-Objekt erstellen und einige Tests von einigen Web-Services zu tun, wie:

[TestMethod()] 
    public void LoginTest() 
    { 
     HttpResponseMessage response = Request.CreateResponse(_accountController.Login("andrew", "DefaultPassword")); 
     Assert.IsTrue(response.IsSuccessStatusCode, "User unable to log in with correct login info"); 

    } 

Hierzu aus dem, was ich aus dem documentation verstanden habe, sollte ich in der Lage sein, so etwas wie:

[TestClass()] 
public class AccountControllerTests : ApiController 
{ 
    Mock<IEducationEntities> _entities = new Mock<IEducationEntities>(MockBehavior.Strict); 
    private AccountController _accountController; 

public AccountControllerTests() { 
     _accountController = new AccountController(_entities.Object); 
     _entities.Setup(table => table.EducationUsers.UsrName).Returns("andrew"); 
     _entities.Setup(table => table.EducationUsers.UsrPwd).Returns("DefaultPassword"); 
} 
[TestMethod] //etc, defining tests below 

dies ist jedoch überhaupt nicht funktioniert, da die Einheiten aus dem databse erzeugt keine Informationen über Subfeldern enthalten offenbar, und ich erhalte die Fehlermeldung:

'DbSet' does not contain a definition for 'UsrPwd' and no extension method 'UsrPwd' accepting a first argument of type 'DbSet' could be found (are you missing a using directive or an assembly reference?)

Was fehlt mir? Wie fülle ich ein moq Objekt mit Testdaten, die die gleiche Struktur wie meine Datenbank haben?

+0

In Ihrer Beispiel Tabellenstruktur wird das Passwort-Feld 'UsrPassword' genannt, aber Sie nennen es' UsrPwd' in Ihrem Test/Mock-Code. –

Antwort

2

This article describes how to mock your Entity Framework context (vorausgesetzt, Sie verwenden Version 6 oder höher)

Sie werden so etwas tun:

[TestMethod] 
public void TestSomething()  
{ 
    // Create the user data 
    var educationUsers = new List<EducationUser> 
    { 
     new EducationUser 
     { 
      UsrName = "andrew", 
      UsrPwd = "DefaultPassword" 
     } 
    }.AsQueryable(); 

    // Create the DbSet that contains the user data and wire it up to return the user data that was created above 
    Mock<DbSet<EducationUser>> educationUsersDbSet = new Mock<DbSet<EducationUser>>(); 
    educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.Provider).Returns(educationUsers.Provider); 
    educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.Expression).Returns(educationUsers.Expression); 
    educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.ElementType).Returns(educationUsers.ElementType); 
    educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.GetEnumerator()).Returns(educationUsers.GetEnumerator()); 

    // Create the mock context and wire up its EducationUsers property to return the DbSet that was created above 
    var context = new Mock<IEducationEntities>(); 
    context.Setup(e => e.EducationUsers).Returns(educationUsersDbSet.Object); 

    // Create the account controller using the mock DbContext 
    _accountController = new AccountController(context.Object); 

    // ... the rest of your testing code ... 
} 

Es wird wohl ärgerlich das Mock DbSet für jeden Entitätstyp zu konfigurieren für alle deine Komponententests, also könntest du eine Methode dafür machen.

public static Mock<DbSet<TEntity>> CreateMockDbSet<TEntity>(IQueryable<TEntity> models) where TEntity : class 
{ 
    Mock<DbSet<TEntity>> dbSet = new Mock<DbSet<TEntity>>(); 

    dbSet.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(models.ElementType); 
    dbSet.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(models.Expression); 
    dbSet.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(models.GetEnumerator()); 
    dbSet.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(models.Provider); 

    return dbSet; 
} 

Dann werden Ihre Testmethode wird

[TestMethod] 
public void TestSomething()  
{ 
    // Create the user data 
    var educationUsers = new List<EducationUser> 
    { 
     new EducationUser 
     { 
      UsrName = "andrew", 
      UsrPwd = "DefaultPassword" 
     } 
    }.AsQueryable(); 

    // Create the DbSet that contains the user data and wire it up to return the user data that was created above 
    Mock<DbSet<EducationUser>> educationUsersDbSet = new CreateMockDbSet(educationUsers); 

    // Create the mock context and wire up its EducationUsers property to return the DbSet that was created above 
    var context = new Mock<IEducationEntities>(); 
    context.Setup(e => e.EducationUsers).Returns(educationUsersDbSet.Object); 

    // Create the account controller using the mock DbContext 
    _accountController = new AccountController(context.Object); 

    // ... the rest of your testing code ... 
} 
+0

Das oben Gesagte war auch der Ansatz, den ich nehmen würde, bis ich anfing, das async/await-Muster zu implementieren. Wenn Sie den bereitgestellten Link lesen, erklärt dies, dass dieser Ansatz nicht funktioniert. Auch der Ansatz, den sie für async/await bereitstellen, funktioniert nicht mit EF Core. Ich benutze die UseInMemoryDatabase von EF Core jetzt für Unit-Tests bis zur Repository-Ebene mit viel Erfolg. Wenn Sie sich für ein Beispiel interessieren, stelle ich eins zur Verfügung. – MORCHARD

+1

Ja, ich würde gerne ein Beispiel sehen. –

Verwandte Themen