1

我在模拟我的代码以使我能够测试我的 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。我被定义

        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

我已经尝试了很多演员表和咒语来让它发挥作用,但我很难过。有谁知道如何正确模拟这些对象?或者如果我从根本上错过了什么?

4

1 回答 1

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

我现在要去羞愧地低下头。

于 2012-12-05T10:50:06.200 回答