Mock是Telerik®JustMock框架中的主要类。Mock用于创建实例和静态模拟,安排和验证行为。
本文将介绍 “Mock”的基本用法:
首先我们创建一个IFoo对象
publicinterfaceIFoo { intBar{get;set;} voidToString(); }
创建实例模拟
要创建实Mock实例,您需要使用该Mock.Create
方法或其通用版本Mock.Create<T>
。有了这个,你创建一个虚假的对象,取代你的测试中的真实对象。
var foo =Mock.Create<IFoo>();
此外,您可以指定初始化传递给构造函数参数。
publicclassFoo { publicFoo(int arg) { } }
对应的单元测试如下:
[TestMethod] publicvoidSimpleTestMethod() { //Arrange var foo =Mock.Create(()=>newFoo(1)); //Assert Assert.IsNotNull(foo); }
Arrange
该Arrange
方法用于更改模拟方法或属性调用的行为。它与本节中描述的一个或多个支持的行为一起使用:
· CallOriginal() - 使用原来的方法执行。
· DoInstead() - 调用方法时执行自定义代码。
· Initialize() - 设置所有的框架方法。
· DoNothing() - 忽略呼叫。此方法仅用于可读性,仅适用于void方法。
· MustBeCalled() - 标记该方法在执行测试期间声明它被调用。
· Raise() - 提出嘲笑的事件。
· Raises() - 一旦方法被调用,就提出一个事件。
· Returns() - 使用非void方法返回一个自定义值。
· Throws() - 调用方法后抛出异常。
以下是如何安排方法调用返回自定义指定值的示例。
[TestMethod] publicvoidArrangingAMethodCallToReturnACustomValue() { //Arrange var foo =Mock.Create<IFoo>(); Mock.Arrange(()=> foo.Bar).Returns(10); }
如果你想模拟一个属性集,而不是使用“Arrabge”方法你应该使用“ArrangeSet”方法。下面的例子演示了如何当属性设置为特定值时抛出异常。
[TestMethod] publicvoidArrangingAPropertySetToThrowAnException() { //Arrange var foo =Mock.Create<IFoo>(); Mock.ArrangeSet(()=> foo.Bar=0).Throws<ArgumentException>(); }
Arrange - 使用具有动态值的表达式
该Arrange
方法还允许您在参数表达式中使用动态值。这使您可以对使用lambda表达式的排列进行细化控制。让我们来看看下面的场景:
publicclassBookService { privateIBookRepository repository; publicBookService(IBookRepository repository) { this.repository = repository; } publicBookGetSingleBook(int id) { return repository.GetWhere(book => book.Id== id); } } publicinterfaceIBookRepository { BookGetWhere(Expression<Func<Book,bool>> expression); } publicclassBook { publicintId{get;privateset;} publicstringTitle{get;set;} }
在这里,我们有一个BookService我们用来从知识库中获取特定的书籍。在IBookRepository只有一个方法- GetWhere其用于返回一个Book由附带作为参数λ表达式指定。看看使用lambda表达式来获取具有特定属性的书GetSingleBook的BookService类的方法id。
在下面的测试中,我们在Arrange阶段中使用lambda表达式:
[TestMethod] publicvoidShouldAssertMockForDynamicQueryWhenComparedUsingAVariable() { //Arrange var repository =Mock.Create<IBookRepository>(); var expected =newBook{Title="Adventures"}; var service =newBookService(repository); Mock.Arrange(()=> repository.GetWhere(book => book.Id==1)) .Returns(expected) .MustBeCalled(); //Act var actual = service.GetSingleBook(1); //Assert Assert.AreEqual(actual.Title, expected.Title); }
我们指定,当存储库GetWhere
方法被调用id=
1时,返回的书应该是特定的书。然后我们采取行动 - 我们执行的GetSingleBook
方法,BookService
我们断言预期的书被返回。
从构造函数参数中自动排列虚拟属性集
正如你在上面第一节看到的那样,当你使用时Mock.Create
,你可以指定初始化参数传递给创建的对象的构造函数。当构造函数设置包含在你正在模拟的类型中的虚拟属性的值时,可以用Mock.Create
同样的方法。结果将是虚拟属性的值将被自动排列。我们来看一个演示这个特性的例子:
publicclassItem { publicvirtualstringName{get;set;} publicItem(string name) { Name= name; } } [TestMethod] publicvoidShouldAutoArrangePropertySetInConstructor() { //Arrange var expected ="name"; var item =Mock.Create<Item>(()=>newItem(expected)); //Assert Assert.AreEqual(expected, item.Name); }
Assert- 验证行为
在您安排某些方法/属性调用的行为并执行操作之后,您需要验证返回的结果或一般行为。你用这个Mock.Assert方法做这个。
让我们Assert一个排列方法实际上是被调用的。
[TestMethod] publicvoidTestMethodShowingAssertFunctionality() { //Arrange var foo =Mock.Create<IFoo>(); Mock.Arrange(()=> foo.ToString()).MustBeCalled(); //Act foo.ToString(); //Assert Mock.Assert(foo); }
即使你不安排方法调用,你仍然可以断言该方法是否被调用。您也可以像调用方法一样断言属性获取调用。
[TestMethod] publicvoidTestMethodShowingAssertFunctionalityOnPropGet() { //Arrange var foo =Mock.Create<IFoo>(); Mock.Arrange(()=> foo.Bar).Returns(10); //Act var returnValue =foo.Bar; //Assert Assert.AreEqual(10,returnValue); }
断言属性, “您需要使用”Mock.AssertSet“。为了演示使用的模拟.AssertSet'我们将使用前面提到的行为在这个主题之一,即”MustBeCalled“。我们将验证属性实际上是设置在测试运行。
[TestMethod] publicvoidTestMethodShowingAssertFunctionalityOnPropSet() { //Arrange var foo =Mock.Create<IFoo>(); Mock.ArrangeSet(()=> foo.Bar=0).MustBeCalled(); //Act foo.Bar=0; //Assert Mock.Assert(foo); }
让我们用一个稍微复杂的例子来完成这个话题。您可能会遇到返回值列表的情况。下一个示例演示如何验证返回的项目的数量并声明调用了特定的方法。
对于这个例子,我们将使用以下内容IFooRepository:
publicinterfaceIFooRepository { List<Foo>GetFoos{get;set;} } [TestMethod] publicvoidVerifyingNumbersOfReturnedItemsAndAssertingAMethodIsCalled() { //Arrange var repository =Mock.Create<IFooRepository>(); List<Foo> list =newList<Foo>(){ newFoo(1), newFoo(2), newFoo(3), newFoo(4), newFoo(5) }; Mock.Arrange(()=> repository.GetFoos).Returns(list).MustBeCalled(); //Act IList<Foo> foos = repository.GetFoos; var expected =5; var actual = foos.Count; //Assert Assert.AreEqual(expected, actual); Mock.Assert(repository); }
参考文献: