是否可以对此进行单元测试?
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]将1个用户添加到存储库
_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);
我正试着用这个
进行测试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);
(...)
}
但它在UpdateAsync的第一行死了。测试是错误的还是UpdateAsync实现?有什么方法可以测试吗?
修改
我按照Belogix的建议添加
dbContext.Setup(x => x.Entry(It.IsAny<IdentityUser>()))
.Returns(() => dbContext.Object.Entry(_user));
我认为这让我更接近,但仍然存在非虚拟错误:非虚拟成员的设置无效:x =&gt; x.Entry(It.IsAny())
答案 0 :(得分:5)
有史以来最好的报价:“计算机科学中的所有问题都可以通过另一层次的间接解决” - 巴特勒兰普森。
看起来如果不添加一些额外的抽象就无法直接测试。我必须以这种方式重构我的UpdateAsync方法
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;
}
然后在Initialize
中更新我的测试代码_repository = new Mock<MyRepository<IdentityUser>>(dbContext.Object);
_repository.Setup(x => x.SetEntityStateModified(It.IsAny<IdentityUser>()));
_repository.Setup(x => x.SetPropertyIsModified(It.IsAny<IdentityUser>()));
我的测试终于通过了
[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 :(得分:0)
dbContext中的ChangeTracker跟踪更改并保留更改的实体。所以你可以断言改变后的实体就在其中。
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
));
对于财产,它将是这样的:
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
));
答案 2 :(得分:-1)
看起来你没有正确地存储你的context
...我不在Visual Studio的计算机上,所以这里有一些伪代码可以证明我的意思。如果您想处理不同的响应,请将IsAnything
替换为您的模拟框架忽略参数或实际上是用户。
// 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]);