(一)安装结果(SetupResult)
有时候在模拟对象中需要一个方法的返回值,而不在意这个方法是否被调用。就可以通过安装结果(SetupRestult)来设置返回值,而绕开期望安装,且可以使用多次。从依赖的角度来说是这样的:方法a(或属性)被方法b使用,而在其它的位置c处方法a又会被使用,而在c处使用之前,不保证是否在b处使用且修改了方法a的返回值。意思就是保证方法a的返回结果是固定的,是忽略它的依赖,而在它该用的位置使用它恒定的值。安装结果可以达到这种效果。
{
public virtual int DescriptionId{ get ; set ;}
public virtual void PrintDescription()
{
DescriptionId = 1 ;
}
}
属性DesriptionId 被方法PrintDescription() 依赖。
public void TestSetupResult()
{
MockRepository mocks = new MockRepository();
var customer = mocks.DynamicMock < Customer > ();
SetupResult.For(customer.DescriptionId).Return( 10 );
Expect.Call( delegate { customer.PrintDescription(); }).Repeat.Times( 2 );
mocks.ReplayAll();
customer.PrintDescription();
customer.PrintDescription();
Assert.AreEqual( 10 , customer.DescriptionId);
}
从这段测试中可以看到,对customer的DescriptionId属性进行了结果安装,只让这个属性返回10。而在随后对依赖它的方法进行了期望安装,且可以被调用2次。但DescriptionId的值仍是10。
Expect.Call(delegate { customer.PrintDescription(); }).Repeat.Times(2);
这句是对不带返回值的方法进行期望安装,当然可以使用Lambda来进行。这个匿名方法就是一个不带参数,没有返回值的委托,这个就相当于Action<>,通过lambda就是:()=>customer.PrintDescription(),完整就是:
Expect.Call(()=>customer.PrintDescription()).Repeat.Times(2);
关于匿名方法和Action<T>委托可见:
http://www.cnblogs.com/jams742003/archive/2009/10/31/1593393.html
http://www.cnblogs.com/jams742003/archive/2009/12/23/1630737.html
安装结果有两种方法:
For和On,For在上边已经使用,On的参数是mock object。对于上边的示例中的粗体部分用On来实现为:
这个也可以通过期望的选项来实现。例如:
.Repeat.Any()
.IgnoreArguments();
其中的粗体部分,可以多次使用,且忽略参数。
(二)约束(Constraints)
约束用来对期望的参数进行规则约束。系统提供了大量内建的约束方法,当然也可以自定义。这里直接贴一张官网给出的列表,一目了然:
约束 | 说明 | 例子 | 接受的值 | 拒绝的值 |
Is | 任何 | Is.Anything() | {0,"","whatever",null, etc} | Nothing Whatsoever |
等于 | Is.Equal(3) | 3 | 5 | |
不等于 | Is.NotEqual(3) | null, "bar" | 3 | |
无 | Is.Null() | null | 5, new object() | |
不为无 | Is.NotNull() | new object(), DateTime.Now | null | |
指定类型 | Is.TypeOf(typeof(Customer)) or Is.TypeOf<Customer>() | myCustomer, new Customer() | null, "str" | |
大于 | Is.GreaterThan(10) | 15,53 | 2,10 | |
大于等于 | Is.GreaterThanOrEqual(10) | 10,15,43 | 9,3 | |
小于 | Is.LessThan(10) | 1,2,3,9 | 10,34 | |
小于等于 | Is.LessThanOrEqual(10) | 10,9,2,0 | 34,53,99 | |
匹配 | Is.Matching(Predicate<T>) |
|
| |
相同 | Is.Same(object) |
|
| |
不相同 | Is.NotSame(object) |
|
| |
Property | 等于值 | Property.Value("Length",0) | new ArrayList() | "Hello", null |
无 | Property.IsNull ("InnerException") | new Exception ("exception without inner exception") | new Exception ("Exception with inner Exception", new Exception("Inner") | |
不为无 | Property.IsNotNull ("InnerException") | new Exception ("Exception with inner Exception", new Exception("Inner") | new Exception ("exception without inner exception") | |
List | 集合中包含这个元素 | List.IsIn(4) | new int[]{1,2,3,4}, new int[]{4,5,6} | new object[]{"",3} |
集合中的元素(去重) | List.OneOf(new int[]{3,4,5}) | 3,4,5 | 9,1,"" | |
等于 | List.Equal(new int[]{4,5,6}) | new int[]{4,5,6}, new object[]{4,5,6} | new int[]{4,5,6,7} | |
Text | 以…字串开始 | Text.StartsWith("Hello") | "Hello, World", "Hello, Rhino Mocks" | "", "Bye, Bye" |
以…字串结束 | Text.EndsWith("World") | "World", "Champion Of The World" | "world", "World Seria" | |
包含 | Text.Contains("or") | "The Horror Movie...", "Either that or this" | "Movie Of The Year" | |
相似 | Text.Like ("rhino|Rhinoceros|rhinoceros") | "Rhino Mocks", "Red Rhinoceros" | "Hello world", "Foo bar", Another boring example string" |
例子:
public void TestConstraints()
{
MockRepository mocks = new MockRepository();
var customer = mocks.DynamicMock < ICustomer > ();
Expect.Call(customer.ShowTitle( "" ))
.Return( " 字符约束 " )
.Constraints(Rhino.Mocks.Constraints
.Text.StartsWith( " cnblogs " ));
mocks.ReplayAll();
Assert.AreEqual( " 字符约束 " , customer.ShowTitle( " cnblogs my favoured " ));
}
它的意思就是如果参数以cnblogs开头,则返回期望值。可以比较一下Moq的参数约束设置方法:
http://www.cnblogs.com/jams742003/archive/2010/03/02/1676197.html
除了上述方法外,rhinomock约束还支持组合,即与,非,或。还以上例进行:
public void TestConstraints()
{
MockRepository mocks = new MockRepository();
var customer = mocks.DynamicMock < ICustomer > ();
Expect.Call(customer.ShowTitle( "" ))
.Return( " 字符约束 " )
.Constraints(
Rhino.Mocks.Constraints.Text.StartsWith( " cnblogs " )
&& Rhino.Mocks.Constraints.Text.EndsWith( " ! " )
);
mocks.ReplayAll();
Assert.AreEqual( " 字符约束 " , customer.ShowTitle( " cnblogs my favoured! " ));
}
参数的条件就是以cnblogs开头,且以!号结束。