私はMoqを初めて使用し、データのバッキングストアのように使用したいと考えていますが、ライブデータベースには触れません。
私の設定は次のとおりです。
これが私のこれまでのテストです:
// ARRANGE
var user = new User()
{
FirstName = "Some",
LastName = "Guy",
EmailAddress = "[email protected]",
};
var mockSet = new MockDbSet<User>();
var mockContext = new Mock<WebAPIDbContext>();
mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object);
// ACT
using (var uow = UnitOfWork.Create(mockContext.Object))
{
uow.UserRepository.Add(user);
uow.SaveChanges();
}
// ASSERT
mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once());
ユーザーがモックDbSetに追加されたことを確認できるため、私のテストは成功したようですが、実際にそのデータを取得してさらにアサーションを実行する必要があります(これは単なるアドホックテストです)。
テストフレームワークが頭を悩ませていることをアドバイスしてください。また、他のテストフレームワークが使いやすい場合は、他のテストフレームワークに移行することもできます。
ありがとうございました。
更新:これが私の作業コードです。
ユニットテスト
// ARRANGE
var user = new User()
{
FirstName = "Some",
LastName = "Guy",
EmailAddress = "[email protected]",
};
var mockSet = new MockDbSet<User>();
var mockContext = new Mock<WebAPIDbContext>();
mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object);
// ACT
using (var uow = UnitOfWork.Create(mockContext.Object))
{
uow.UserRepository.Add(user);
uow.SaveChanges();
}
// ASSERT
mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once());
// TODO: Further assertations can now take place by accessing mockSet.BackingStore.
}
MockDbSet
class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class
{
public ICollection<TEntity> BackingStore { get; set; }
public MockDbSet()
{
var queryable = (this.BackingStore ?? (this.BackingStore = new List<TEntity>())).AsQueryable();
this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider);
this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression);
this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType);
this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator());
// Mock the insertion of entities
this.Setup(e => e.Add(It.IsAny<TEntity>())).Returns((TEntity entity) =>
{
this.BackingStore.Add(entity);
return entity;
});
// TODO: Other DbSet members can be mocked, such as Remove().
}
}
バッキングストアとして機能するコレクションを作成し、バッキングコレクションで設定された列挙データベースをモックする必要があります。
public class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class {
public MockDbSet(List<TEntity> dataSource = null) {
var data = (dataSource ?? new List<TEntity>());
var queryable = data.AsQueryable();
this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider);
this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression);
this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType);
this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator());
//Mocking the insertion of entities
this.Setup(_ => _.Add(It.IsAny<TEntity>())).Returns((TEntity arg) => {
data.Add(arg);
return arg;
});
//...the same can be done for other members like Remove
}
}
これで、リストを使用してデータを保持できます
// ARRANGE
var dataSource = new List<User>(); //<-- this will hold data
var user = new User()
{
FirstName = "Some",
LastName = "Guy",
EmailAddress = "[email protected]",
};
var mockSet = new MockDbSet<User>(dataSource);
var mockContext = new Mock<WebAPIDbContext>();
mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object);
// ACT
using (var uow = UnitOfWork.Create(mockContext.Object))
{
uow.UserRepository.Add(user);
uow.SaveChanges();
// ASSERT
mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once());
Assert.IsTrue(dataSource.Contains(user)); //<-- shows mock actually added item
Assert.IsTrue(uow.UserRepository.Any(u => u == user)); //<-- show you can actually query mock DbSet
}