(一)安装结果(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开头,且以!号结束。