.net 如何使用Rhino.Mocks模拟特定代码?

.net 如何使用Rhino.Mocks模拟特定代码?,.net,mocking,rhino-mocks,.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

我有以下代码:

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(),
    };
  }
}
我希望使用
ireresponse
IEntityRepository
模拟对
FlowFolderHandler.Post
方法进行单元测试。我当前的实现使用以下手动模拟:

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(); }
  }
}
我的问题是,如果没有使用Rhino.mock的手动mock
EntityRepositoryMock
ResponseMock
,如何编写相同的单元测试(或多或少)

谢谢

编辑


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

出于好奇,您的“手动”模拟会给您带来麻烦,还是您只是在寻找一种更干净的方法来实现它们?有时,“手动”方式是最好(最简单)的方式,因为大多数模拟框架都有自己的问题集

尽管如此,模仿类的基本步骤如下:

  • 创建MockRepository对象
  • 要求MockRepository对象创建类/接口的模拟。有很多不同类型的模拟,你可以要求(动态,部分,存根等),你需要阅读文档,找出一个适合你
  • 使用Do()处理程序让您的mock执行您想要的特定代码位(看起来这就是您在上面所做的,特别是使用EntityRepositoryMock.Update)
  • Do()处理程序记录在此处:

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

    模拟类的一个技术限制是 mock对象调用目标类构造函数,这是由于mock 从目标类派生

    这是本页讨论的主题:

    还有一个要点是模拟属性,您应该指定
    PropertyBehaviour()

    编辑:检查方法是否被调用过一次

    repositoryMock.AssertWasCalled(m => m.Update(), mi => mi.Repeat.Once());
    
    有用的链接:

    • 有关良好的示例和说明,请参见

    关于构造器-我编辑了这篇文章。总的来说,你的回答是RTFM的一种非常礼貌的形式,这是完全合法的,但我更希望有一个现成的例子,我将从中找出其余的。我无意让人觉得你是RTFM(尽管看了我的文章,我想你是对的).从你的帖子中,我不确定你以前是否使用过Rhino.Mocks,所以我只是尝试用Do()处理程序给出大致的方向。看起来sll为你提供了一个更具体的答案。我正在尝试实现你的建议。第一个问题-Repeat.Many()有什么用?接下来,我尝试模拟响应。
    responseMock.Expect(m=>m.Headers).PropertyBehavior();
    不起作用,因为
    Headers
    是只读属性。调用
    Headers
    属性时,如何让模拟返回某个对象?抱歉,
    Repeat.Any()
    。它指示即使多次调用方法也应返回指定的返回值,您可以通过
    Repeat.Once()将其转换为单个方法调用,这样下次调用mocked methiod时将返回null而不是返回值(显然对于返回类型不是void的方法),这适用于
    WhenCalled()
    ,它将在每次调用方法时执行,而不仅仅是第一次time@mark:关于属性,若要模拟返回值,请仅使用
    responseMock.Expect(m=>m.Headers).return(Myproperty)
    并在Myproperty中抛出exception.Myproperty-测试类中定义的属性。若要测试异常,请使用
    Assert.Throws()=>responseMock.Headers)
    很好,它可以工作。还有一个问题,我如何确保
    Update
    方法只调用一次?
    // Mocks
    var repositoryMock = MockRepository.GenerateMock<IEntityRepository>();
    var responseMock = MockRepository.GenerateMock<IResponse>();
    
    repositoryMock.Expect(m => m.Update(null)).IgnoreArguments.WhenCalled(
       mi =>
       {
          IEntityBase passedInEntity = mi.Args[0] as IEntityBase;
          EntityRepository.ApplySaveSideEffects(passedInEntity, id, entityRelation); 
       }
    ).Repeat.Any();
    
    repositoryMock.Expect(m => m.Entity).Proeprtybehaviour();
    
    repositoryMock.AssertWasCalled(m => m.Update(), mi => mi.Repeat.Once());