如何使用Rhino.Mocks模拟某个代码?

时间:2011-11-10 11:15:53

标签: .net mocking rhino-mocks

我有以下代码:

public interface IFlowFolderHandler
{
  OperationResult Post(FlowFolder dto);
}

public class FlowFolderHandler : IFlowFolderHandler
{
  private readonly IResponse m_response;
  private readonly IEntityRepository m_entityRepository;

  public FlowFolderHandler(IResponse response, IEntityRepository entityRepository)
  {
    m_response = response;
    m_entityRepository = entityRepository;
  }

  public OperationResult Post(FlowFolder dto)
  {
    var ent = FlowFolderX.Cast(dto, true);
    m_entityRepository.Update(ent);
    var id = EntityIdComparer.IdToString(ent.Id);
    m_response.Headers["X-Entity-Id"] = id;
    return new OperationResult.Created
    {
      RedirectLocation = new Uri("FlowFolder/" + id, UriKind.Relative),
      ResponseResource = ent.GetEntityRelation(),
    };
  }
}

我希望使用FlowFolderHandler.PostIResponse模拟对IEntityRepository方法进行单元测试。我目前的实现是使用以下手动模拟:

private class EntityRepositoryMock : IEntityRepository
{
  private readonly Action<IEntityBase> m_update;
  public EntityRepositoryMock(int id, EntityRelation entityRelation)
  {
    m_update = ent => EntityRepository.ApplySaveSideEffects(ent, id, entityRelation);
  }
  public IEntityBase Fetch(EntityId entityId) { throw new NotImplementedException(); }
  public void FetchByExpression(Type entityType, Expression expr, IList list, List<Pair<string, bool>> orderBy) { throw new NotImplementedException(); }
  public void Update(IEntityBase entity) { m_update(entity); }
}

private class ResponseMock : IResponse
{
  public ResponseMock() { Headers = new HttpHeaderDictionary(); }
  public IHttpEntity Entity { get { throw new NotImplementedException(); } }
  public HttpHeaderDictionary Headers { get; private set; }
  public void WriteHeaders() { throw new NotImplementedException(); }
  public bool HeadersSent { get { throw new NotImplementedException(); } }
  public int StatusCode
  {
    get { throw new NotImplementedException(); }
    set { throw new NotImplementedException(); }
  }
}

单元测试是:

[Test]
[Factory("YieldPostFlowFolderData")]
public void PostFlowFolder(int id, Uri uri, EntityRelation entityRelation, FlowFolder flowFolder)
{
  var entityRepository = new EntityRepositoryMock(id, entityRelation);
  var response = new ResponseMock();
  var handler = new FlowFolderHandler(response, entityRepository);

  var result = handler.Post(flowFolder);

  Assert.AreEqual((int)HttpStatusCode.Created, result.StatusCode);
  Assert.AreEqual(id, int.Parse(response.Headers["X-Entity-Id"]));
  Assert.AreEqual(uri, result.RedirectLocation);
  SUC.Utils.AssertDeepEqual(entityRelation, result.ResponseResource);
}

我的问题是如何在没有使用Rhino.Mocks的手动模拟EntityRepositoryMockResponseMock的情况下编写相同的单元测试(或多或少)?

感谢。

修改

我的手动模拟只包含构造函数,因为它们是手动模拟。我可以添加一个专用的方法PrepareMock而不是构造函数,以确保模拟已准备好...模拟。自动模拟,由Rhino.Mocks创建的模拟,不会有任何与构造函数相关的问题,因为我会模拟接口而不是具体类型。

2 个答案:

答案 0 :(得分:2)

// Mocks
var repositoryMock = MockRepository.GenerateMock<IEntityRepository>();
var responseMock = MockRepository.GenerateMock<IResponse>();

使用Expect()可以设置你想要的任何期望,例如exp [update()方法的ectation,它只是一个做某事而不是抛出异常:

repositoryMock.Expect(m => m.Update(null)).IgnoreArguments.WhenCalled(
   mi =>
   {
      IEntityBase passedInEntity = mi.Args[0] as IEntityBase;
      EntityRepository.ApplySaveSideEffects(passedInEntity, id, entityRelation); 
   }
).Repeat.Any();

另一个重点是模拟属性,您应该指定PropertyBehaviour()

repositoryMock.Expect(m => m.Entity).Proeprtybehaviour();

编辑:检查该方法是否曾被调用

repositoryMock.AssertWasCalled(m => m.Update(), mi => mi.Repeat.Once());

有用的链接:

答案 1 :(得分:0)

出于好奇,您的“手动”嘲笑是否会给您带来麻烦,或者您只是在寻找更清洁的方式来实施它们?有时候,“手动”方式是最好的(最简单的)方式,因为大多数模拟框架都有自己的问题。

无论如何,说完了,像你一样嘲笑类的基本步骤:

  1. 创建MockRepository对象
  2. 要求MockRepository对象创建类/接口的模拟。你可以要求很多不同类型的模拟(动态,部分,存根等等),你需要阅读文档来找出哪一个适合你。
  3. 使用Do()处理程序让你的mocks执行你想要的特定代码位(看起来这就是你在上面所做的,特别是EntityRepositoryMock.Update
  4. 这里记录了Do()处理程序: http://ayende.com/wiki/Rhino+Mocks+The+Do()+Handler.ashx

    您的模拟对象在构造函数中也有代码。仅供参考,您可能会遇到构造函数的一些问题。来自Ayende:

      

    模拟类的技术限制是创建一个   由于mock,mock对象调用目标类构造函数   来自目标类。

    这是来自这个讨论ctors的页面: http://ayende.com/wiki/Rhino+Mocks+Mocking+classes.ashx