目前,我正在使用EF6在UnitOfWork中实现我的存储库。我还创建了一个In-Memory模拟实现(MockUnitOfWork& MockRepository),以便我可以在单元测试中使用它们,但是我现在必须处理对象的繁琐设置。
这不是Autofixture的目的吗?我如何获得可以在我的测试中使用的MockUnitOfWork,其中包含已填充的 Foo 和 Barr 存储库?我使用NSubstitute作为我的模拟框架。
IUnitOfWork
public interface IUnitOfWork
{
void Save();
void Commit();
void Rollback();
IRepository<Foo> FooRepository { get; }
IRepository<Bar> BarRepository { get; }
}
IRepository
public interface IRepository<TEntity> where TEntity : class
{
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null);
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
答案 0 :(得分:1)
您正在尝试进行功能测试,因此拥有一个功能数据库是明智的。
EF可以使用测试连接字符串在setup和teardown方法中重新创建和销毁数据库。这将为您的测试提供真实的功能测试环境,以防止模仿真实环境。
例如:
[TestFixtureSetUp]
public static void SetupFixture() //create database
{
using (var context = new XEntities())
{
context.Setup();
}
}
[TestFixtureTearDown]
public void TearDown() //drop database
{
using (var context = new XEntities())
{
context.Database.Delete();
}
}
[SetUp]
public void Setup() //Clear entities before each test so they are independent
{
using (var context = new XEntities())
{
foreach (var tableRow in context.Table)
{
context.Table.Remove(tableRow);
}
context.SaveChanges();
}
}
答案 1 :(得分:0)
是的,这正是它的目的。请参阅下面的示例。我使用Mock而不是NSubstitute,因为我不熟悉NSubstitute。您只需要传递另一个自定义,并在设置中使用NSubstitute语法。
[SetUp]
public void SetUp()
{
// this will make AutoFixture create mocks automatically for all dependencies
_fixture = new Fixture()
.Customize(new AutoMoqCustomization());
// whenever AutoFixture needs IUnitOfWork it will use the same mock object
// (something like a singleton scope in IOC container)
_fixture.Freeze<Mock<IUnitOfWork>>();
// suppose YourSystemUnderTest takes IUnitOfWork as dependency,
// it'll get the one frozen the line above
_sut = _fixture.Create<YourSystemUnderTest>();
}
[Test]
public void SomeTest()
{
var id = _fixture.Create<object>(); // some random id
var fooObject = _fixture.Create<Foo>(); // the object repository should return for id
// setuping THE SAME mock object that wa passed to _sut in SetUp.
// _fixture.Freeze<Mock part is ESSENTIAL
// _fixture.Freeze<Mock<IUnitOfWork>>() returns the mock object, so whatever comes
// next is Mock specific and you'll have to use NSubstitute syntax instead
_fixture.Freeze<Mock<IUnitOfWork>>()
.Setup(uow => uow.FooRepository.GetById(id))
.Returns(fooObject);
// if this method will ask the unit of work for FooRepository.GetById(id)
// it will get fooObject.
var whatever = _sut.SomeMethod(id);
// do assertions
}
关于AutoFixture的美妙之处在于,您不必为所测试系统的所有依赖项创建模拟。如果您正在测试仅使用一个依赖项的功能,则只需在 创建被测系统之前将其冻结。其余的依赖项将自动模拟。