15

目前我正在使用 EF6 在 UnitOfWork 中实现我的存储库。我还创建了一个 In-Memory 模拟实现(MockUnitOfWork 和 MockRepository),以便我可以在单元测试中使用它们,但是我现在必须处理繁琐的对象设置。

这不是 Autofixture 的设计初衷吗?我将如何获得一个可以在我的测试中使用的 MockUnitOfWork,其中包含填充的FooBarr存储库?我正在使用 NSubstitute 作为我的模拟框架。

工作单位

public interface IUnitOfWork
{
    void Save();
    void Commit();
    void Rollback();

    IRepository<Foo> FooRepository { get; }
    IRepository<Bar> BarRepository { get; }
}

存储库

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

2 回答 2

1

您正在尝试在这里进行功能测试,因此拥有一个功能数据库是明智之举。

EF 可以使用测试连接字符串在设置和拆卸方法中重新创建和销毁数据库。这将为您的测试提供一个真实的功能测试环境,以模拟真实环境。

前任:

        [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();
            }
        }
于 2014-10-10T12:23:36.513 回答
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 的美妙之处在于您不必为被测系统的所有依赖项创建模拟。如果您正在测试仅使用一个依赖项的功能,您只需在创建被测系统之前冻结它。其余的依赖项将被自动模拟。

于 2014-07-26T12:33:00.360 回答