使用RhinoMocks和NUnit测试模拟的EF上下文,上下文和工作单元

时间:2012-12-04 19:30:59

标签: asp.net-mvc entity-framework repository-pattern unit-of-work rhino-mocks-3.5

我在模拟我的代码时遇到了实际问题,使我能够测试我的MVC控制器。

我的存储库实现了以下接口

public interface IEntityRepository<T>
{
    IQueryable<T> All { get; }
    IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties);
    void Delete(int id);
    T Find(int id);
    void InsertOrUpdate(T entity);
    void InsertOrUpdateGraph(T entity);
}

喜欢这样

public interface IMonkeyRepository : IEntityRepository<Monkey>
{
}

我的EF上下文实现了以下接口

public interface IMonkeyContext
{
    IDbSet<Monkey> Monkeys { get; set; }
    DbEntityEntry Entry(object entity);
    IEnumerable<DbEntityValidationResult> GetValidationErrors();
    int SaveChanges();
}

我的工作单元接口定义如下

public interface IUnitOfWork<TContext> : IDisposable
{
    TContext Context { get; }
    int Save();
} 

并实施

public class MonkeyUnitOfWork : IUnitOfWork<IMonkeyContext>
{

    private readonly IMonkeyContext context;
    private bool disposed;
    public MonkeyUnitOfWork(IMonkeyContext context)
    {
        this.context = context;
    }
    public IMonkeyContext Context
    {
        get
        {
            return this.context;
        }
    }
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public int Save()
    {
        var ret = this.context.SaveChanges();
        return ret;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                ((DbContext)this.context).Dispose();
            }
        }

        this.disposed = true;
    }
}

我有一个MonkeyController whos创建我希望测试的动作。我被定义了

        if (this.ModelState.IsValid)
        {
            this.repo.InsertOrUpdate(Mapper.Map<MonkeyModel, Monkey>(monkey));
            this.uow.Save();
            return this.RedirectToAction(MVC.Monkey.Index());
        }

        return this.View(monkey);

在我的单元测试中,我正在使用RhinoMocks并定义了测试

[TestFixture]
public class MonkeyControllerTests
{
    MockRepository mocks = null;

    private IMonkeyRepository monkeyRepository;

    private IMonkeyContext context;

    private MonkeyUnitOfWork unitOfWork;       

    private MonkeyController controller;

    [SetUp]
    public virtual void SetUp()
    {
        TestHelpers.SetupAutoMap();

        this.monkeyRepository = this.Mocks.StrictMultiMock<IMonkeyRepository>(typeof(IEntityRepository<Monkey>));

        this.context = this.Mocks.StrictMock<IMonkeyContext>();

        this.unitOfWork = new MonkeyUnitOfWork(this.context);

        this.controller = new MonkeyController(this.MonkeyRepository, this.unitOfWork);
    }

    [TearDown]
    public virtual void TearDown()
    {
        if (this.mocks != null)
        {
            try
            {
                this.mocks.ReplayAll();
                this.mocks.VerifyAll();
            }
            finally
            {
                this.mocks = null;
            }
        }
    }

    public MockRepository Mocks
    {
        get
        {
            if (mocks == null)
                mocks = new MockRepository();
            return mocks;
        }
    }

    [Test]
    public void MonkeyCreateShouldShouldDoSomeStuff()
    {
        var monkeyModel = ViewModelTestHelpers.CreateSingleMonkey();
        var monkey = Mapper.Map<MonkeyModel, Monkey>(monkeyModel);

        this.monkeyRepository.Expect(action => action.InsertOrUpdate(monkey));

        this.context.Expect(action => action.SaveChanges()).Return(1);
        var result = (RedirectToRouteResult)this.controller.Create(monkeyModel);

        Assert.AreEqual(MVC.Monnkey.ActionNames.Index, result.RouteValues["action"]);
    }
}

当我运行我的测试时,我得到以下错误

上一个方法'IMonkeyContext.SaveChanges();'需要返回值或抛出异常。

或者它抱怨IEntityRepository.InsertOrUpdate期望1实际为0

我已经尝试了很多演员和咒语来让这个工作,但我很难过。有谁知道如何正确模拟这些对象?或者,如果我基本上错过了一些东西?

1 个答案:

答案 0 :(得分:1)

好吧,这似乎是一个小学生的错误

当RhinoMocks表示没有调用IEntityRepository.InsertOrUpdate时,它是正确的。

我在测试中从视图模型映射到模型的代码行

var monkey = Mapper.Map<MonkeyModel, Monkey>(monkeyModel);

然后在期望

中使用它
this.monkeyRepository.Expect(action => action.InsertOrUpdate(monkey));

当然告诉Rhino应该使用这个确切的猴子实例调用该函数。

该功能当然在动作中以下列方式调用

this.repo.InsertOrUpdate(Mapper.Map<MonkeyModel, Monkey>(monkey));

不一样的实例。

我现在已经转移到aaa语法并将测试代码更改为

this.monkeyRepository.Stub(r => r.InsertOrUpdate(Arg<Monkey>.Is.Anything));

并断言

this.monkeyRepository.AssertWasCalled(r => r.InsertOrUpdate(Arg<Monkey>.Is.Anything));

我现在要羞愧地垂头丧气。