(一)安装结果(SetupResult)
有时候在模拟对象中需要一个方法的返回值,而不在意这个方法是否被调用。就可以通过安装结果(SetupRestult)来设置返回值,而绕开期望安装,且可以使用多次。从依赖的角度来说是这样的:方法a(或属性)被方法b使用,而在其它的位置c处方法a又会被使用,而在c处使用之前,不保证是否在b处使用且修改了方法a的返回值。意思就是保证方法a的返回结果是固定的,是忽略它的依赖,而在它该用的位置使用它恒定的值。安装结果可以达到这种效果。
public class Customer
{
public virtual int DescriptionId{get;set;}
public virtual void PrintDescription()
{
DescriptionId=1;
}
}
属性DesriptionId被方法PrintDescription()依赖。
[Test]
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来实现为:
SetupResult.On(customer).Call(customer.DescriptionId).Return(10);
这个也可以通过期望的选项来实现。例如:
Expect.Call(customer.DescriptionId).Return(10)
.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"
|
例子:
[Test]
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约束还支持组合,即与,非,或。还以上例进行:
[Test]
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开头,且以!号结束。
网友评论