2014-09-10 10 views
8

È possibile eseguire il test dell'unità?Test dell'unità non riuscito su EF Entry.State

public class MyRepository<T> where T : IdentityUser, new() 
{ 
    public async Task UpdateAsync(T user) 
    { 
     _context.Entry(user).State = EntityState.Modified; 
     _context.Entry(user).Property("UserName").IsModified = false; 
     await _context.SaveChangesAsync(); 
    } 
} 

Il [TestInitialize] aggiunge 1 utente nel repository

_user = new IdentityUser { Id = "70a038cdde40" }; 

IDbSet<IdentityUser> users = new FakeDbSet<IdentityUser> { _user }; 

var dbContext = new Mock<MyDbContext<IdentityUser>>(); 
dbContext.Setup(x => x.Users).Returns(() => users); 

_repository = new MyRepository<IdentityUser>(dbContext.Object); 

e sto cercando di testare con questo

private MyRepository<IdentityUser> _repository; 

[TestMethod] 
public async Task UpdateUser_Success2() 
{ 
    var user = await _repository.FindByIdAsync("70a038cdde40"); 
    Assert.IsFalse(user.EmailConfirmed, "User.EmailConfirmed is True"); 

    user.EmailConfirmed = true; 

    await _repository.UpdateAsync(user); 

    (...) 
} 

Ma muore il 1 ° linea di UpdateAsync. Il test è errato o l'implementazione UpdateAsync? C'è un modo per testarlo?

Modifica

ho aggiunto come suggerito da Belogix

dbContext.Setup(x => x.Entry(It.IsAny<IdentityUser>())) 
         .Returns(() => dbContext.Object.Entry(_user)); 

Che mi si avvicina, penso, ma hanno ancora l'errore non virtuale: l'installazione non valido su un membro non virtuale: x => x.Entry (It.IsAny())

+0

Qual è '_context' sul punto si esegue il test? Una finta di qualcosa o una cosa reale (indicando un DB)? Hai soppresso le parti pertinenti in modo tale che la chiamata sia tutta scandagliata? – Belogix

+0

@Belogix Ho aggiornato la mia domanda spero che risponda al tuo – kooshka

+0

No, chiudi ma se guardi la mia risposta devi imitare 'Entry' per restituire' utente' NOT 'Stato' in quanto proprietà della tua classe ... Quindi usa il mio esempio di beffeggiamento 'Entry' e riprova ... In questo modo puoi impostare lo stato ecc. Su quell'oggetto fittizio. Spero che abbia senso! – Belogix

risposta

5

Miglior citazione mai: "Tutti i problemi dell'informatica possono essere risolti da un altro livello di riferimento indiretto" - Butler Lampson.

Sembra che questo non possa essere testato direttamente senza aggiungere un'ulteriore astrazione. Ho dovuto refactoring il mio metodo UpdateAsync questo modo

public async Task UpdateAsync(T user) 
{ 
    SetEntityStateModified(user); 
    SetPropertyIsModified(user); 
    await _context.SaveChangesAsync(); 
} 

public virtual void SetPropertyIsModified(T user) 
{ 
    _context.Entry(user).Property("UserName").IsModified = false; 
} 

public virtual void SetEntityStateModified(T user) 
{ 
    _context.Entry(user).State = EntityState.Modified; 
} 

E poi aggiornare il mio codice di prova nel inizializzazione

_repository = new Mock<MyRepository<IdentityUser>>(dbContext.Object); 
_repository.Setup(x => x.SetEntityStateModified(It.IsAny<IdentityUser>())); 
_repository.Setup(x => x.SetPropertyIsModified(It.IsAny<IdentityUser>())); 

La mia prova poi finalmente passa

[TestMethod] 
public async Task can_update_user_details() 
{ 
    //Arrange 
    var user = await _repository.Object.FindByIdAsync("70a038cdde40"); 
    Assert.IsFalse(user.EmailConfirmed, "User.EmailConfirmed is True"); 

    //Act    
    user.EmailConfirmed = true; 

    await _repository.Object.UpdateAsync(user); 
    var newUser = await _repository.Object.FindByIdAsync("70a038cdde40"); 

    //Assert 
    Assert.IsTrue(newUser.EmailConfirmed, "User.EmailConfirmed is False"); 
} 
-1

Sembra che tu non abbia corretto il tuo context correttamente ... Io non sono in un computer con Visual Studio, quindi qui c'è qualche pseudo codice che dovrebbe dimostrare ciò che io significare. Sostituisci il IsAnything con il tuo modo di ignorare l'argomento o in realtà l'utente se desideri gestire risposte diverse.

// Existing context initialisation... 
var dbContext = new Mock<MyDbContext<IdentityUser>>(); 
dbContext.Setup(x => x.Users).Returns(() => users); 

// NEW: Mock what/how Entry is going to return when called (i.e. return a user) 
dbContext.Setup(x => x.Entry(IsAnything)).Returns(() => users[0]); 
+3

Questo non funzionerà poiché Entry non è virtuale in EntityFramework, quindi non è ragionabile – tocqueville

0

Il ChangeTracker in DbContext tiene traccia delle modifiche e tenere le entità che sono cambiate. Quindi puoi affermare che l'entità cambiata è tra loro.

Assert.IsTrue(dbContext.Object.ChangeTracker.Entries().Any(entry => 
      entry.State == EntityState.Modified && 
      entry.Entity is IdentityUser && 
      (entry.Entity as IdentityUser).Id == users[0].Id // Here you can check if it is actually the same user 
     )); 

Per la proprietà sarebbe qualcosa di simile:

Assert.IsTrue(_context.Object.ChangeTracker.Entries().Any(entry => 
      entry.Property("UserName").IsModified == false && 
      entry.Entity is IdentityUser && 
      (entry.Entity as IdentityUser).Id == users[0].Id // Here you can check if it is actually the same user 
     )); 
Problemi correlati