Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test failing on EF Entry.State

Is it possible to unit test this?

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

The [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 test 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 it dies on 1st line of UpdateAsync. Is the test that is wrong or the UpdateAsync implementation? Is there any way I can test it?

Edit

I added as suggested by Belogix

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

That gets me closer, I think, but still have the non-virtual error: Invalid setup on a non-virtual member: x => x.Entry(It.IsAny())

like image 587
kooshka Avatar asked Sep 10 '14 14:09

kooshka


1 Answers

Best quote ever: "All problems in computer science can be solved by another level of indirection" - Butler Lampson.

It looks like this can't be tested directly without adding some additional abstraction. I had to refactor 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 my test code in the Initialize

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

My test then finally 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");
}
like image 148
kooshka Avatar answered Oct 26 '22 19:10

kooshka