代码改变世界

RhinoMock入门(6)——Do,With和Record-playback(转载)

2013-08-08 11:01  mch.zhang  阅读(294)  评论(0)    收藏  举报

RhinoMock入门(7)——Do,With和Record-playback

 

(一)Do(delegate)

有时候在测试过程中只返回一个静态的值是不够的,在这种情况下,Do()方法可以用来在方法调用时添加自定义的行为。一般来说,Do()方法会替换方法调用。它的返回值会从模拟的调用中返回(即使是有异常发生也是这样)。Do()的参数委托委托的方法的签名须和方法的签名匹配。只有当签名匹配时才能生效,且一个匹配生效一次。

看官方给出的例子:

publicclass Speaker
{
   
privatereadonlystring firstName;
   
privatereadonlystring surname;
   
private INameSource nameSource;

   
public Speaker(string firstName, string surname, INameSource nameSource)
    {
       
this.firstName = firstName;
       
this.surname = surname;
       
this.nameSource = nameSource;
    }

   
publicstring Introduce()
    {
       
string name = nameSource.CreateName(firstName, surname);
       
returnstring.Format("Hi, my name is {0}", name);
    }
}
 
 

 

publicinterface INameSource
{
   
string CreateName(string firstName, string surname);
}

 

 

现在演讲者和名字分开在两个类中。然后进行自我介绍,介绍时要介绍自己的姓名,即FirstName+LastName。在介绍中要用到InameSource中的CreateName方法,接下来将会模拟这个接口,而通过其它的方法来替代。

 

[Test]
publicvoid SayHelloWorld()
{
    MockRepository mocks
=new MockRepository();
    INameSource nameSource
= mocks.DynamicMock<INameSource>();

    Expect.Call(nameSource.CreateName(
null, null))
          .IgnoreArguments()
          .Do(
new NameSourceDelegate(Formal));

    mocks.ReplayAll();
   
string expected ="Hi, my name is Ayende Rahien";
   
string actual =new Speaker("Ayende", "Rahien", nameSource).Introduce();
    Assert.AreEqual(expected, actual);
}

delegatestring NameSourceDelegate(string first, string surname);

privatestring Formal(string first, string surname)
{
   
return first +""+ surname;
}
 
 

 

 

看上段测试的粗体部分。

Do参数是委托类型,其中这个委托类型委托的方法的签名要和模拟对象中期望的要替换的方法的签名一致,即:

private string Formal(string first, string surname)
string CreateName(string firstName, string surname);

 

两者相匹配。

然后当对演讲者构造时: new Speaker("Ayende", "Rahien", nameSource)

会对演讲者三个域进行赋值

private readonly string firstName;
private readonly string surname;
private INameSource nameSource;

 

接下来进行介绍时,调用方法:

 

publicstring Introduce()
{
   
string name = nameSource.CreateName(firstName, surname);
   
returnstring.Format("Hi, my name is {0}", name);
}

 

而这个方法则由Do方法的委托参数委托的方法来替代:

privatestring Formal(string first, string surname)
{
   
return first +""+ surname;
}

 

返回FirstName+空格+LastName

(二)With

流畅式的期望和验证语法。什么是流畅式?先看例子:

[Test]
publicvoid TestFluent()
{
    MockRepository mocks
=new MockRepository();
    var customer
= mocks.DynamicMock<ICustomer>();

   
string strTemp=string.Empty;

    With.Mocks(mocks)
        .Expecting(
         
delegate
          {
             Expect.Call(customer.ShowTitle(
"")).Return("with 语句");
          })
        .Verify(
        
delegate
          {
             strTemp
= customer.ShowTitle("");
          });

    Assert.AreEqual(
"with 语句", strTemp);
}
 
 

 

这就是所谓的流畅式。通过匿名委托来实现。如果在匿名委托中完成则会隐匿调用ReplayAll()和mocks.VerifyAll()。

如果要启用次序,则可使用:ExpectingInSameOrder,例如:

 

[Test]
publicvoid TestFluent()
{
    MockRepository mocks
=new MockRepository();
    var customer
= mocks.DynamicMock<ICustomer>();
   
string strTemp=string.Empty;
    With.Mocks(mocks).ExpectingInSameOrder(
       
delegate
        {
           Expect.Call(customer.ShowTitle(
"")).Return("with 语句");
           Expect.Call(customer.Unid).Return(
1);
        })
       .Verify(
      
delegate
       {
          strTemp
= customer.ShowTitle("");
         
int i = customer.Unid;
       });

    Assert.AreEqual(
"with 语句", strTemp);
}
 
 

 

With语句的隐式使用

With可以隐式的创建Mock实例,并自动调用VerifyAll方法。

[Test]
publicvoid TestWithMocker()
{
    With.Mocks(
       
delegate
        {
          var customer
= Mocker.Current.DynamicMock<ICustomer>();
          Expect.Call(customer.ShowTitle(
"")).Return("with 语句");
          Mocker.Current.ReplayAll();

          Assert.AreEqual(
"with 语句", customer.ShowTitle(""));
        });
}
 
 

 

这里才看出With确实很流畅。

下边说一下由显式创建Mock实例来代替隐式创建:

[Test]
publicvoid TestWithMockerr()
{
    MockRepository mocks
=new MockRepository();
    With.Mocks(mocks,
      
delegate
       {
          var customer
= Mocker.Current.DynamicMock<ICustomer>();
          Expect.Call(customer.ShowTitle(
"")).Return("with 语句");

          Mocker.Current.ReplayAll();

          Assert.AreEqual(
"with 语句", customer.ShowTitle(""));
       });
}
 
 

 

没多大区别。在使用Mocker.Current时,不能在嵌套中使用,因为这是个全局的,而With.Mocks会重写Mocker.Current

 

(三)Record-PlayBack

Rhinomock支持一种通过Using语句来进行录制回放的方式。

 

[Test]
publicvoid TestRecordPlayback()
{
    MockRepository mocks
=new MockRepository();
    var customer
= mocks.DynamicMock<ICustomer>();

   
using (mocks.Record())
    {
        Expect.Call(customer.ShowTitle(
"")).Return("录制回放");
    }

   
using (mocks.Playback())
    {
        Assert.AreEqual(
"录制回放", customer.ShowTitle(""));
    }
}