Unit test crash in EF Entry.State

Is this possible for unit test?

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

[TestInitialize] adds 1 user to the 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); 

and I'm trying to check with this

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

But he dies on the first line of UpdateAsync. Is the test incorrect or an implementation of UpdateAsync? Is there any way to check this?

Edit

I added as Belogix suggested

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

This is closer to me, I think, but still have a non-virtual error: incorrect setting for a non-virtual element: x => x.Entry (It.IsAny ())

+8
c # unit-testing entity-framework
source share
3 answers

The best quote of all: "All problems in computer science can be solved by a different level of indirection" - Butler Lampson.

It seems like this cannot be verified directly without adding an extra abstraction. I had to reorganize my UpdateAsync method this way

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

And then update your test code in the Initialize file

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

Then my test passes

 [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"); } 
+5
source share

ChangeTracker in dbContext tracks changes and holds entities that have changed. That way you can claim that the changed object is among them.

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

For a property, it will be something like this:

 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 )); 
0
source share

It looks like you didn’t type your context correctly ... I'm not on a computer with Visual Studio, so here is some kind of pseudo code that should demonstrate what I mean. Replace IsAnything any of the mocking frameworks to ignore the argument, or actually the user, if you want to handle different answers.

 // 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 (ie return a user) dbContext.Setup(x => x.Entry(IsAnything)).Returns(() => users[0]); 
-one
source share

All Articles