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