What is a mocking framework? Why is it useful?
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 Driver
class. 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 FakeVehicle
class 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:
不论相不相信,只有几行代码就可以代替FakeVehicle
class的需要了。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.Object
. mock.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 IVehicle
; Mock<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?的更多相关文章
- Testing with a mocking framework (EF6 onwards)
When writing tests for your application it is often desirable to avoid hitting the database. Entity ...
- 什么是Mocking framework?它有什么用?
原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why-is-it-useful 今天我想讲下关于mocking fr ...
- Mocking framework
[译] 什么是Mocking framework?它有什么用? 原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why ...
- 什么是Mocking framework?它有什么用?(转)
今天我想讲下关于mocking frameworks,并且解释下他为什么有用处.我将给你们展示用和不用mocking framework两种测试方法. 假设我们已经有了一个Driver类: publi ...
- Googletest - Google Testing and Mocking Framework
Googletest - Google Testing and Mocking Framework https://github.com/google/googletest
- 利用Mocking Framework 单元测试Entity Framework
一.前言 在实际编写程序时,往往需要与数据库打交道,在单元测试中直接使用数据库又显得太重,如果可以方便的编写一些测试数据,这样更易于检测功能.如何模拟数据库行为便是本篇的主题.微软有教程说明Moq E ...
- JustMock Lite (Free Mocking Framework For .net)
通过 Nuget 安装 2. 官网下载(官网不行点这里) 3. 帮助文档 商业版和免费版区别概览 MockingContainer 测试类准备:一般来说也是业务类 public class C ...
- 第一篇:Entity Framework 简介
先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发O ...
- Entity Framework版本历史概览
转自:http://www.cnblogs.com/fecktty2013/archive/2014/09/26/entityframework-overview.html EF版本 .net fra ...
随机推荐
- A Neural Algorithm of Artistic Style
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/53931536 1. 资源 Paper: ...
- excel模板解析—桥接模式:分离解析模板和业务校验
在做excel模板解析的时候,其实会有两个部分,第一,将模板读取出来,校验一些必录项等. 但除了这些,在数据真正被业务线使用的时候,还会有一些其他的校验,比如说:根据业务,年龄是不能超过多少岁的,包括 ...
- .Net MVC断点进不去
.Net MVC断点进不去 1.httpget httppost 2.启动项设为UI 3.基于页面没错误的情况下
- PHP文件操作函数及文件指针理解
知识点: 一.fopen(),文件打开函数,读写参数有: 1.R : 只读,指针在文件开头 2.r+:读写,指针同上 3.W :只写,写入前会删除文件内容,然后指针回到文件开头,文件不存在则创建 4 ...
- UVA1316 Supermarket
题目描述 有一个商店有许多批货,每一批货又有N(0<=N<= 10^4104 )个商品,同时每一样商品都有收益 P_iPi ,和过期时间 D_iDi (1<= Pi,DiPi,D ...
- 在Ignite中使用k-最近邻(k-NN)分类算法
在本系列前面的文章中,简单介绍了一下Ignite的线性回归算法,下面会尝试另一个机器学习算法,即k-最近邻(k-NN)分类.该算法基于对象k个最近邻中最常见的类来对对象进行分类,可用于确定类成员的关系 ...
- Nodejs 网络爬虫(资讯爬虫) 案例
1. superagent superagent 是一个流行的nodejs第三方模块,专注于处理服务端/客户端的http请求.在nodejs中,我们可以使用内置的http等模块来进行请求的发送.响应处 ...
- freescale 16位单片机的地址映射
以MC9S12XS128MAL为例,其实DG128之类的类似.如图一,128代表的是单片机中的FLASH大小为128K Byte,同理64代表的是单片机中的FLASH大小为64 K Byte,256代 ...
- python的资源整合
一位大牛整理的Python资源 Python基本安装: * http://www.python.org/ 官方标准Python开发包和支持环境,同时也是Python的官方网站:* http://www ...
- 【Tomcat】一台电脑上运行多个tomcat
效果: 1.首先需要安装Tomcat7,Tomcat8. Tomcat7: Tomcat8: 2.添加两个环境变量,添加CATALINA_HOME1和CATALINA_BASE1指向E:\tomcat ...