Today I want to talk about mocking frameworks and why they are useful. In order to do that I first need to propose a scenario to you in which we will be testing a piece of functionality in an application. I will show you how you would test it without a mocking framework, and then I will show you how to test it with one.

今天我想来谈谈mocking frameworks和为什么他们这么有用。为了说明这一点我首先给出了一些功能代码。我会展示给你如果不是用mocking framework我们需要如何测试。

Let's pretend we have a driver class like this: 假设我们有一个下面这样的driver类

Notice that our Driver class has a dependency on an interface called IVehicle. Let's define that interface.

注意我们的driver类有一个接口IVehicle的依赖。让我们定义这个接口

Now that we have our Driver class we need to write a couple unit tests for it. Before we can do that however, we have to figure out what we are going to pass into the constructor to satisfy the dependency on IVehicle. Many people would think at this point that they need to finish whatever component implements the IVehicle interface before they can test the Driverclass. That is not the case. In fact, if you passed a completed component for IVehicle you might as well not even write unit tests. The whole point of unit testing is to test things in isolation. Testing the Driver class with a full-fledged version of IVehicle is not unit testing; that is getting closer to integration testing which is a whole different ball game. If a test on your Driver class fails, you couldn't be sure it was the Driver class's fault or if something went wrong within the class that was passed in as a dependency.

既然我们有了我们的dirver类就需要为它写单元测试。但是在我们写之前我们需要搞清楚传入什么参数才可以满足IVehicle的依赖。许多人可能认为在他们测试driver类之前无论如何都需要完成执行IVehicle接口。事实上,如果你传递一个完整的IVehicle进去你可能就不是在写单元测试。单元测试的重点是独立测试。如果你的dirver类失败了,你可能无法确认是dirver类失败了还是传入其中的依赖类操作失败了。

The fact that the dependency is an interface makes this an easy fix. We will just create a fakeimplementation of IVehicle.

依赖是一个接口使得它看来是容易解决的。我们可以仅仅创建一个IVehicle的假操作

Notice the global integers we defined? In our unit tests we would like a way to verify that the HonkHorn() and ApplyBrakes() methods actually got called and how many times they got called. Now that we have something we can pass into our Driver class when we instantiate it, we can write our tests. We want to test two behaviors: Can a driver evade trouble? And can a driver evade trouble while alerting the offending driver to his mistake?

注意到全局integers的定义了吗?在我们的单元测试中我们期望确定honkhorn()和applybrakes()方法的确得到了调用。既然我们有了在实例化dirver类时可以传递给driver类的数据,我们就可以写自己的测试了。我们想测试两个操作:Can a driver evade trouble? And can a driver evade trouble while alerting the offending driver to his mistake?

This is all great. We have a successful unit test that verifies both that the EvasiveManeuvers()method returns true and that the ApplyBrakes() method on the implementing class of IVehicle was called exactly one time in both tests, as well as the HonkHorn() method was called exactly once in the second test and never in the first test. Take note that in real Test Driven Development (TDD) we would have written the tests first, and then wrote the code we were testing. However, for our purposes it was easier to show you what we had and how we might test it.

There is one thing that is rather annoying about writing tests in this manner. We have to write a special class (FakeVehicle) in order to even instantiate Driver. Writing a special class for every dependency can get VERY tiring. This is where a mocking framework comes in. The framework I am going to use is called Moq; it's syntax is unique but after using it for a bit I think you'll agree that it is very fluent and easy to write. Make sure you have the Moq.dll assembly referenced in your project and that your unit test class has the using Moq; declaration at the top. Now let's rewrite our unit tests to use Moq and then I will explain it in greater detail afterward.

这样做很棒。我们成功进行了单元测试来保证EvasiveManeuvers()方法返回true并且ApplyBrakes和HonkHorn也被成功调用了。

但是这样的话我们就必须为了实例化Driver来写一个特定的类FakeVehicle。为每一个依赖写特定的类是非常辛苦的。这就是mocking framework出现的原因了。

Believe it or not, with only a few lines of code we got rid of the need for the FakeVehicleclass to exist. Moq took our interface and dynamically built a class that implements it behind the scenes. By default all the members of the class it built would return default values. Since the default value of a Boolean is false, the HonkHorn() and ApplyBrakes() methods on the mocked class would return false. Obviously we want them to return true when called. To accomplish this we simply make use of Moq's Setup() method. This method accepts a lambda expression which allows you to navigate to the method on the interface that you want to define in a strongly-typed manner. If this is confusing, picture the alternative; if Moq did not accept a lambda expression then you would have to give it a method name in a magic string, like this:

不论相不相信,只有几行代码就可以代替FakeVehicleclass的需要了。moq用了我们的接口并且动态创建了一个类来在后台执行。默认的所有的类成员都返回默认值。因为boolean的默认值是false,所以HonkHorn()和 ApplyBrakes()方法就都会返回false。显然的我们想调用时另其返回true。为了实现这点,我们只是简单实用了moq的setup()方法。

Once you have all that setup you can instantiate the component you are testing and pass in the mocked object by calling mock.Objectmock.Object is a really generic sounding property to store the mocked object we created, but that's where it is stored. Do not try to pass the instance of Mock<T> itself into your component. It can be confusing at first but remember that your Driver needs an instance of IVehicleMock<T> is not of type IVehicle, it is of type Mock<T>. To get the created instance of IVehicle you must access the Object property on your instance of Mock<T>. In other words:

一旦你初始化了所有想测试的组建并且传递了mocked object。mock.object就是一个保存在mocked object中的属性。不要将Mock<T>本身传递到你的组建中去。driver需要的是IVehicle类型的实例,Mock<T>不是这个类型的,而是 Mock<T>类型的。为了得到IVehicle实例,你必须访问Mock<T>实例属性object,换句话说:

After that you can go ahead and perform whatever functions you intend to test. In our case we called driver.EvasiveManeuvers(alertOffendingDriver) and tested that the returned result was true. The next thing we tested was how many times the HonkHorn() and ApplyBrakes() methods were called on the dependency class. To do this with the fake class we created we had to actually add fields to track how many times the methods were called. With Moq we don't have to do anything. It automatically tracks how many times we called the method. All we have to do is call mock.Verify() passing in a lambda with the method we want to check and the number of times we expected it to be called. If the verify fails it will throw an exception, causing our test to fail.

在那之后你可以去执行任何你想测试的功能。在我们的例子中调用driver.EvasiveManeuvers(alertOffendingDriver) 并且返回true。接下来的事情是测试HonkHorn() and ApplyBrakes()调用了几次。实用moq我们不需要做任何事情,它会自动追踪我们调用了多少次这个方法。我们需要做的是调用mock.Verify()

In its most basic form that is the usage of Moq. Hopefully now you can see why mocking frameworks are so valued and how Moq accomplishes its task. Post any questions in the comments below. I assure you that I read each and every one of them that same day.

What is a mocking framework? Why is it useful?的更多相关文章

  1. Testing with a mocking framework (EF6 onwards)

    When writing tests for your application it is often desirable to avoid hitting the database.  Entity ...

  2. 什么是Mocking framework?它有什么用?

    原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why-is-it-useful 今天我想讲下关于mocking fr ...

  3. Mocking framework

    [译] 什么是Mocking framework?它有什么用? 原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why ...

  4. 什么是Mocking framework?它有什么用?(转)

    今天我想讲下关于mocking frameworks,并且解释下他为什么有用处.我将给你们展示用和不用mocking framework两种测试方法. 假设我们已经有了一个Driver类: publi ...

  5. Googletest - Google Testing and Mocking Framework

    Googletest - Google Testing and Mocking Framework https://github.com/google/googletest

  6. 利用Mocking Framework 单元测试Entity Framework

    一.前言 在实际编写程序时,往往需要与数据库打交道,在单元测试中直接使用数据库又显得太重,如果可以方便的编写一些测试数据,这样更易于检测功能.如何模拟数据库行为便是本篇的主题.微软有教程说明Moq E ...

  7. JustMock Lite (Free Mocking Framework For .net)

    通过 Nuget 安装 2.   官网下载(官网不行点这里) 3.   帮助文档 商业版和免费版区别概览 MockingContainer 测试类准备:一般来说也是业务类 public class C ...

  8. 第一篇:Entity Framework 简介

    先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发O ...

  9. Entity Framework版本历史概览

    转自:http://www.cnblogs.com/fecktty2013/archive/2014/09/26/entityframework-overview.html EF版本 .net fra ...

随机推荐

  1. ocrosoft Contest1316 - 信奥编程之路~~~~~第三关 问题 L: 大整数减法

    http://acm.ocrosoft.com/problem.php?cid=1316&pid=11 题目描述 求两个大的正整数相减的差.   输入 共2行,第1行是被减数a,第2行是减数b ...

  2. J2EE的十三个技术——EJB之消息驱动JMS

    JMS--Java Message Service JAVA的消息服务,消息可实现两端通信. 用于访问面向消息中间件的标准api,他提供与厂商无关的访问方法,以访问消息收发服务. 特点:即使其中一方不 ...

  3. qemu中device和driver的区别 使用9p文件系统

    qemu配置中经常会出现-driver/-device的选项,可以理解成-driver是后端设备,即一个实际的物理的磁盘:device是把这块磁盘插入到虚机中的pci控制器中. 这样的话,虚机也能看到 ...

  4. Redis键管理

    Redis键管理 Redis 键命令用于管理 redis 的键. 语法 Redis 键命令的基本语法如下: redis > COMMAND KEY_NAME redis > SET w3c ...

  5. nio的reactor模式

    转自:http://blog.csdn.net/it_man/article/details/38417761 线程状态转换图 就是非阻塞IO 采用多路分发方式举个例子吧,你服务器做一个聊天室,按照以 ...

  6. linux——rhel安装yum

    在进行下面的操作之前,一定要确保网络正常,如果没有网络,下面的所有操作一个都不能实现.(下次会写个本地源的配置,这个就可以离线的状态下进行,需要用到系统的镜像文件,安装好系统之后不要删掉.) 首先配置 ...

  7. hibernate中类状态转换

  8. eclipse keys

    Navigate Open Declaration F3 Editing Script Source Source Mark Occurrences Alt+Shift+O Editing PHP s ...

  9. lxml.html删除节点树和tag对

    # encoding: utf-8import StringIO from apihelper import info, info_savefrom lxml import etree, htmlfr ...

  10. 非常好的博客!!!linux内存管理概述【转】

    转自:http://blog.csdn.net/bullbat/article/details/7166140 inux内存管理建立在基本的分页机制基础上,在linux内核中RAM的某些部分将会永久的 ...