JustMock测试你的应用程序

本主题将指导您通过几个简单的步骤来使用Telerik®JustMock轻松测试您的应用程序。您将理解一个简单的原理,称为Arrange / Act / Assert,并熟悉框架中的核心方法和属性,这些方法和属性在最常见的测试场景中使用

为了说明下一个例子中JustMock的用法,我们将使用一个样本仓库(warehouse)和一个依赖订单对象(Order)。仓库持有不同产品的库存。订单包含产品和数量。

仓库界面和订单类看起来像这样:

publicdelegatevoidProductRemoveEventHandler(string productName,int quantity);

publicinterfaceIwarehouse

{

    eventProductRemoveEventHandlerProductRemoved;

    stringManager{get;set;}

    boolHasInventory(string productName,int quantity);

    voidRemove(string productName,int quantity);

}

publicclassOrder

{

    publicOrder(string productName,int quantity)

    {

        this.ProductName= productName;

        this.Quantity= quantity;

    }

    publicstringProductName{get;privateset;}

    publicintQuantity{get;privateset;}

    publicboolIsFilled{get;privateset;}

    publicvoidFill(Iwarehouse warehouse)

    {

        if(warehouse.HasInventory(this.ProductName,this.Quantity))

        {

            warehouse.Remove(this.ProductName,this.Quantity);

        }

    }

    publicvirtualstringReceipt(DateTime orderDate)

    {

        returnstring.Format("Ordered {0} {1} on{2}",this.Quantity,this.ProductName, orderDate.ToString("d"));

    }

}

方法

DoInstead

DoInstead当您想要通过用自定义操作替换方法来更改方法的行为时,可以使用该方法。我们用上面的例子来说明如何使用DoInstead

[TestMethod]

    publicvoidDoInstead_TestMethod()

    {

        //Arrange

        var warehouse =Mock.Create<Iwarehouse>();

        var order =newOrder("Camera",2);

        bool called =false;

        Mock.Arrange(()=> warehouse.HasInventory("Camera",2)).DoInstead(()=> called =true);

        //Act

        order.Fill(warehouse);

        //Assert

        Assert.IsTrue(called);

}

简单的说 -
我们安排,当仓库的HasInventory方法调用参数“camera”和2,我们将执行行动“ ()=>called=true ”,而不是调用实际的方法。

CallOriginal

在某些情况下,您可能希望在调用原始方法实现时使用特定的值调用该方法,并使用其他值调用模拟。为此,您可以使用该CallOriginal方法。

[TestMethod]

    publicvoidCallOriginal_TestMethod()

    {

        //Arrange

        var order =Mock.Create<Order>(Behavior.CallOriginal,"Camera",2);

        Mock.Arrange(()=> order.Receipt(DateTime.Today)).CallOriginal();

        Mock.Arrange(()=> order.Receipt(Arg.Matches<DateTime>(d => d >DateTime.Today))).Returns("InvalidDateTime");

        //Act

        var callWithToday =order.Receipt(DateTime.Today);

        var callWithDifferentDay = order.Receipt(DateTime.Today.AddDays(1));

        //Assert

        Assert.AreEqual("Ordered 2 Camera on "+DateTime.Today.ToString("d"), callWithToday);

        Assert.AreEqual("Invalid DateTime", callWithDifferentDay);

}

在这个例子中,我们安排当order.Receipt用参数调用DateTime.Today方法时,应该调用原来的方法实现。但是,一旦晚于日期调用相同的方法,DateTime.Today我们将返回Invalid
DateTime

throws

Throws当你想抛出一个异常特定方法调用方法时使用。在下面的例子中,我们抛出一个无效的操作异常,试图调用仓库删除零个数量。

[TestMethod]

    [ExpectedException(typeof(InvalidOperationException))]

    publicvoidThrows_TestMethod()

    {

        //Arrange

        var order =newOrder("Camera",0);

        var warehouse =Mock.Create<Iwarehouse>();

        //Set up that the ware house has inventory of any products with any quantities.

        Mock.Arrange(()=> warehouse.HasInventory(Arg.IsAny<string>(),Arg.IsAny<int>())).Returns(true);

        //Set up that call to warehouse.Remove with zero quantity is invalid and throwsan exception.

        Mock.Arrange(()=> warehouse.Remove(Arg.IsAny<string>(),Arg.Matches<int>(x => x ==0)))

                    .Throws(newInvalidOperationException());

        //Act

        order.Fill(warehouse);

}

在这种情况下,我们使用ExpectedException属性Microsoft.VisualStudio.TestTools.UnitTesting来验证类型InvalidOperationException的异常是否被抛出。

Machers

匹配器让你忽略传递实际值作为模拟中使用的参数。相反,它们给你传递一个满足参数类型或期望值范围的表达式的可能性。例如,如果方法接受字符串作为第一个参数,则不需要传递特定的字符串,如“Camera”,而是可以使用Arg.IsAny<string>()

JustMock支持三种类型的匹配器:

1.   Arg.IsAny<[Type]>();

2.   Arg.IsInRange([FromValue : int], [ToValue : int],[RangeKind])

3.   Arg.Matches(Expression> expression)

我们来看看它们的详细用法。

Arg.IsAny();

我们已经在上面的一个例子中使用了这个匹配器。

Mock.Arrange(()=> warehouse.HasInventory(Arg.IsAny<string>(),Arg.IsAny<int>())).Returns(true);

这个匹配器指定当HasInventory任何字符串作为第一个参数调用方法,任何int作为第二个参数时,它应该返回true

Arg.IsInRange(int
from,int to,RangeKind range)

IsInRange匹配器让我们安排一个预期值范围的调用。通过RangeKind论证,我们可以指定给定的范围是包含还是排除其边界。

对于范围从到的参数值,将返回以下内容true

Mock.Arrange(()=> foo.Echo(Arg.IsInRange(0,5,RangeKind.Inclusive))).Returns(true);

Arg.Matches (Expression>
expression)

这是最灵活的匹配器,它允许你指定你自己的匹配表达式。我们用一个简单的例子来说明:

Mock.Arrange(()=> foo.Echo(Arg.Matches<int>( x => x <10)).Returns(true);

属性

在上面的例子中,我们只模拟方法,但是你也可以用同样的方法来模拟属性。

[TestMethod]

    publicvoidMockingProperties_TestMethod()

    {

        //Arrange

        var warehouse =Mock.Create<Iwarehouse>();

        Mock.Arrange(()=> warehouse.Manager).Returns("John");

        string manager =string.Empty;

        //Act

        manager = warehouse.Manager;

        //Assert

        Assert.AreEqual("John", manager);

}

另外,还可以给属性赋值

[TestMethod]

    [ExpectedException(typeof(StrictMockException))]

    publicvoidMockingProperties_PropertySet_TestMethod()

    {

        //Arrange

        var warehouse =Mock.Create<Iwarehouse>(Behavior.Strict);

        Mock.ArrangeSet(()=> warehouse.Manager="John");

        //Act

        warehouse.Manager="Scott";

}

在安排步骤中,我们设置仓库经理只能设置为“John”。但是在行动步骤中,我们将经理设置为“Scott”。这抛出了一个模拟异常。请记住,这只会在您使用StrictBehavior创建模拟时才起作用

另一个常用的技巧是断言将属性设置为特定值会引发异常。我们来安排一下

[TestMethod]

    [ExpectedException(typeof(ArgumentException))]

    publicvoidMockingProperties_PropertySet_Throws_TestMethod()

    {

        //Arrange

        var warehouse =Mock.Create<Iwarehouse>();

        Mock.ArrangeSet(()=> warehouse.Manager="John").Throws<ArgumentException>();

        //Act

        //that's ok

        warehouse.Manager="Scott";

        //but that would throw an ArgumentException

        warehouse.Manager="John";

}

在这里,我们使用Throws上面讨论的方法来表明如果warehouse.Manager设置为“John”,则应抛出异常。

活动

该方法Raises允许您在调用方法时引发事件并传递特定的事件参数。回到我们的仓库示例,我们可能想要在调用ProductRemovedRemove方法时引发事件。

[TestMethod]

    publicvoidRaisingAnEvent_TestMethod()

    {

        //Arrange

        var warehouse =Mock.Create<Iwarehouse>();

        Mock.Arrange(()=> warehouse.Remove(Arg.IsAny<string>(),Arg.IsInRange(int.MinValue,int.MaxValue,RangeKind.Exclusive)))

            .Raises(()=> warehouse.ProductRemoved+=null,"Camera",2);

        string productName =string.Empty;

        int quantity =0;

        warehouse.ProductRemoved+=(p, q)=>{ productName = p; quantity =q;};

        //Act

        warehouse.Remove(Arg.AnyString,Arg.AnyInt);

        //Assert

        Assert.AreEqual("Camera", productName);

        Assert.AreEqual(2, quantity);

}

在安排步骤中,我们设置一旦仓库的Remove方法被调用,我们将ProductRemoved用参数“Camera”和2 来提升调用事件。

项目GitHub地址:https://github.com/liuzhenyulive/JustMockDemo

参考文献:http://docs.telerik.com/devtools/justmock/getting-started/quick-start#testing-your-application-with-justmock

JustMock .NET单元测试利器(三)用JustMock测试你的应用程序的更多相关文章

  1. JustMock .NET单元测试利器(一)

    1.什么是Mock? Mock一词是指模仿或者效仿,用于创建实例和静态模拟.安排和验证行为.在软件开发中提及"mock",通常理解为模拟对象.模拟对象的概念就是我们想要创建一个可以 ...

  2. JustMock .NET单元测试利器(二)JustMock基础

    JustMock API基础 Mock是Telerik®JustMock框架中的主要类.Mock用于创建实例和静态模拟,安排和验证行为. 本文将介绍 "Mock"的基本用法: 首先 ...

  3. 单元测试利器 JUnit 4

    引言 毋庸置疑,程序员要对自己编写的代码负责,您不仅要保证它能通过编译,正常地运行,而且要满足需求和设计预期的效果.单元测试正是验证代码行为是否满足预期的有效手段之一.但不可否认,做测试是件很枯燥无趣 ...

  4. [转]单元测试利器 JUnit 4

    引言 毋庸置疑,程序员要对自己编写的代码负责,您不仅要保证它能通过编译,正常地运行,而且要满足需求和设计预期的效果.单元测试正是验证代码行为是否满足预期的有效手段之一.但不可否认,做测试是件很枯燥无趣 ...

  5. PHP单元测试利器:PHPUNIT初探

    开始动手安装phpunit 本文中将通过介绍php中的单元测试利器phpunit(http://phpunit.de/),并通过实际例子来讲解如何在实际工作中运用phpunit.首先安装phpunit ...

  6. 【Linux探索之旅】第一部分第三课:测试并安装Ubuntu

    内容简介 1.第一部分第三课:测试并安装Ubuntu 2.第一部分第四课预告:磁盘分区 测试并安装Ubuntu 大家好,经过前两个比较偏理论(是否想起了带着瓜皮帽,手拿折扇的老学究,或者腐儒)的课程, ...

  7. Spring+SpringMVC+MyBatis+easyUI整合优化篇(三)代码测试

    日常啰嗦 看到标题你可能会问为什么这一篇会谈到代码测试,不是说代码优化么?前两篇主要是讲了程序的输出及Log4j的使用,Log能够帮助我们进行bug的定位,优化开发流程,而代码测试有什么用呢?其实测试 ...

  8. Android单元测试之四:仪器化测试

    Android单元测试之四:仪器化测试 仪器化测试 在某些情况下,虽然可以通过模拟的手段来隔离 Android 依赖,但代价很大,这种情况下可以考虑仪器化的单元测试,有助于减少编写和维护模拟代码所需的 ...

  9. 20175316盛茂淞 《java程序设计》第三周课堂测试错题总结

    20175316盛茂淞 <java程序设计>第三周课堂测试错题总结 出现问题 错题总结 题目1 在Ubuntu中用自己的有位学号建一个文件,教材p87 Example4_15 1. 修改代 ...

随机推荐

  1. BZOJ 4176: Lucas的数论 [杜教筛]

    4176: Lucas的数论 题意:求\(\sum_{i=1}^n \sum_{j=1}^n \sigma_0(ij)\) \(n \le 10^9\) 代入\(\sigma_0(nm)=\sum_{ ...

  2. BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]

    传送门 题面太美不忍不放 分块分块 这种题的一个特点是只有查询,通常需要预处理:加入修改的话需要暴力重构预处理 预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][ ...

  3. Docker Compose容器编排

    Compose是Docker官方的开源项目,可以实现对Docker容器集群的快速编排.Compose 中有两个重要的概念:服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实 ...

  4. 用 k8s 运行一次性任务 - 每天5分钟玩转 Docker 容器技术(132)

    容器按照持续运行的时间可分为两类:服务类容器和工作类容器. 服务类容器通常持续提供服务,需要一直运行,比如 http server,daemon 等.工作类容器则是一次性任务,比如批处理程序,完成后容 ...

  5. Windows Server 2016-部署RODC只读域控制器

    只读域控制器Read-Only Domain Controller简称RODC.RODC是Windows Server 2008之后引入的一活动目录特性,与其他域控制器一样包含AD数据库,但RODC默 ...

  6. Promise对象的简单用法

    要了解一个东西,首先要从,它是什么.用来做什么以及怎么取用它这三个方面来了解. 首先,promise是什么? 我们来参考一下MDN对它的定义: Promise 对象用于一个异步操作的最终完成(或失败) ...

  7. PHP 支持8种基本的数据类型

    四种标量类型: boolean (布尔型):这是最简单的类型,只有两种取值,可以为 TRUE/true 或 FALSE/false ,不区分大小写.详细请查看:PHP布尔类型(boolean)inte ...

  8. [Python Study Notes]Socket模拟ssh执行cmd并记录遇到的问题

    服务器端: 流程: 1.创建servert实例 2.绑定地址和端口 3.开始监听 4.创建客户端连接实例 5.等待客户端的消息 6.......... # The_author = 'liu66' # ...

  9. hiveql笔记(一)

    1.创建表 create table if not exists mydb.employees{ name String COMMENT 'Employee name', salary FLOAT C ...

  10. MacbookPro管理员问题

    更改用户名重启之后,发现用户名还是用户名,管理员权限降成了普通用户. 参考这个帖子改的用户名: https://zhidao.baidu.com/question/259845860.html 找回管 ...