Stub, Mock and Proxy Testing
Mock testing means unit testing with mock objects as substitutes for real objects. By real objects I mean the objects the tested unit (class) will be using in the real application. If you have a class Calculator, that needs a dao (Data Access Object) object to load the data it needs from a database, then the dao object is a "real object". In order to test the Calculator class you will have to provide it with a dao object that has a valid connection to the database. In addition you have to insert the data needed for the test into the database.
Setting up the connection and inserting the data in the database can be a lot of work. Instead you can provide the Calculator instance with a fake dao class which just returns the data you need for the test. The fake dao class will not actually read the data from the database. The fake dao class is a mock object. A replacement for a real object which makes it easier to test the Calculator class. Purist mock testers would call such a fake dao for a stub. I will get to that distinction later.
mock测试意味着使用真实对象的替代品mock对象来进行单元测试。真实对象就是指的会在真实项目中使用的测试对象。如果你有一个calculator类,需要一个dao对象来从数据库加载数据。那么这个时候dao对象就是一个“真实的对象”。为了测试calculator类,你需要提供一个和数据库有有效联系的dao对象。而且你必须向数据库插入需要测试用的数据。
配置同数据库间的联系和插入数据可能需要大量的工作。那么你就可以为calculator实例提供一个假的dao类用来仅仅返回你需要的数据就可以了。这个假的dao类并不会真的去读取数据库的数据。这个假的dao类就是一个nock对象。用来替换真实的对象使得更容易测试calculator类。
个人理解: mock就是对象的复制品。stub可以负责指定需要测试的数据。
The situation of the Calculator using a dao object can be generalized to "a unit that uses a collaborator". The unit is the Calculator and the collaborator is the dao object. I'll express it like this:
unit --> collaborator
The arrow means "uses". When the collaborator is exchanged with a mock (or stub), it would be expressed like this:
unit --> mock
In a unit test situation it will look like this:
unit test --> unit --> collaborator
... or...
unit test --> unit --> mock
Stubs, Mocks, and Proxies
There are three types of fake objects you can use for testing: Stubs, Mocks and Proxies. Remember, a stub, mock, or proxy replaces a collaborator of the tested unit during unit test. The stubs and mocks follows Martin Fowlers definition of stubs and mocks.
A Stub is an object that implements an interface of a component, but instead of returning what the component would return when called, the stub can be configured to return a value that suits the test. Using stubs a unit test can test if a unit can handle various return values from its collaborator. Using a stub instead of a real collaborator in a unit test could be expressed like this:
stub是用来执行组件接口的对象,但是并不是调用组件应当返回的值,stub可以为了单元测试而被配置返回值。使用stubs单元测试就可以处理多种不同的返回值情况用来测试了。
- unit test --> stub
- unit test --> unit --> stub
- unit test asserts on results and state of unit
First the unit test creates the stub and configures its return values. Then the unit test creates the unit and sets the stub on it. Now the unit test calls the unit which in turn calls the stub. Finally the unit test makes assertions about the results of the method calls on the unit.
A Mock is like a stub, only it also has methods that make it possible determine what methods where called on the Mock. Using a mock it is thus possible to both test if the unit can handle various return values correctly, and also if the unit uses the collaborator correctly. For instance, you cannot see by the value returned from a dao object whether the data was read from the database using a Statement or a PreparedStatement. Nor can you see if the connection.close() method was called before returning the value. This is possible with mocks. In other words, mocks makes it possible to test a units complete interaction with a collaborator. Not just the collaborator methods that return values used by the unit. Using a mock in a unit test could be expressed like this:
首先单元测试创建stub并且配置他的返回值。然后单元测试创建单元并且设置stub。现在单元测试调用单元就是调用stub。最后单元测试使用assertions来处理单元的方法调用结果。
mock类似stub,只是他也有方法可以来确定mock调用什么方法和什么时候调用。如果unit可以正确处理多个返回值,那么使用mock就可以都测试到这些结果。可以用来测试交互行为。
- unit test --> mock
- unit test --> unit --> mock
- unit test asserts on result and state of unit
- unit test asserts on the methods called on mock
First the unit test creates the mock and configures its return values. Then the unit test creates the unit and sets the mock on it. Now the unit test calls the unit which in turn calls the mock. Finally the unit test makes assertions about the results of the method calls on the unit. The unit test also makes assertions on what mehods were called on the mock.
首先unit test创建mock并且配置他的返回值。然后单元测试创建单元并且为他们设置mock。现在单元测试调用unit,unit调用mock。最后使用assertion来判断结果。
Proxies in mock testing are mock objects that delegate the method calls to real collaborator objects, but still records internally what methods were called on the proxy. Thus proxies makes it possible to do mock testing with real collaborators. Using a proxy in a unit test could be expressed like this:
- unit test --> collaborator
- unit test --> proxy
- unit test --> unit --> proxy --> collaborator
- unit test asserts on result and state of unit
- unit test asserts on methods called on proxy
First the unit test creates the collaborator. Then the unit test creates the proxy for the collaborator. Third the unit test creates the unit and sets the proxy on it. Now the unit test calls the unit which in turn calls the proxy. Finally the unit test makes assertions about the results of the method calls on the unit. The unit test also makes assertions on what mehods were called on the proxy.
Stub, Mock, and Proxy Testing with Testimonial
There are several popular mock testing API's available. Among others JMock and EasyMock. As of writing these two API's do not support proxies as described above. Note: They *use* java.lang.reflect.Proxy instances to implement their dynamic mocks. But that is not the same as the test proxies described above. These API's can only be used with stubs and mocks, not proxy for real collaborators. I'm sure they'll add it in the future.
For the code examples in this text I will be using my own testing API, Butterfly Testing Tools . I developed Butterfly Testing Tools because I needed the proxy testing feature that neither JMock nor EasyMock has. In addition the API's could be designed a bit more straigtforward and flexible, in my opinion (that, I guess, is a matter of personal style).
First lets see how to create stub for an interface:
Connection connection =
(Connection) MockFactory.createProxy(Connection.class);
The connection variable is a stub of the Connection interface. I can now call methods on the connection instance just as if it was a real database connection. The methods will only return null though, since the stub is not configured to return any special value. In order to configure the stub to return the values appropriate for your test, you must obtain the Mock for the stub. Here is how that is done:
IMock mock = MockFactory.getMock(connection);
Now you have the mock associated with the stub. One of the methods the IMock interface has is
addReturnValue(Object returnValue);
Using the addReturnValue method you can add return values to the stub. You can add as many as you want. The return values will be returned from the stub in the same sequence they were added. Once a return value has been returned it is removed from the stub, just like in a queue. Note: The sequence of added return values must match the sequence of called methods on the stub! If you add a String "myReturnValue" as return value to the stub and then call connection.prepareStatement("select * from houses") which returns a PreparedStatement, you will get an exception. The String return value cannot be returned from the connection.prepareStatement("..."); You will have to make sure yourself that the return values and called methods on the stub match.
Once you have the IMock instance for a stub you can also make assumptions about what methods were called on the stub. The IMock interface has a series of assertCalled(MethodInvocation) methods for this purpose. Here is an example:
mock.assertCalled(new MethodInvocation("close"));
If the connection.close() method has not been called a java.lang.AssertionError is thrown. If you are using JUnit for your unit test JUnit will catch the AssertionError and report that the test failed. There are other assertCalled() etc. methods on the IMock interface. See the Testimonial project for more info.
The last thing I will show is how to make a proxy for a real connection and get the mock associated with the proxy:
//opens a real database connection.
Connection realConnection = getConnection();
Connection proxyConnection = MockFactory.createProxy(realConnection);
IMock mock = MockFactory.getMock(proxyConnection);
Simple, isn't it? It's just the same as when creating stubs for interfaces. You just provide the real collaborator to the MockFactory instead of an interface (class object). The proxyConnection will record all methods called on it before forwarding the method call to the realConnection instance. That way you can use the proxyConnection just as fine as a real connection, and at the same time make mock assertions about what methods were called on it.
You can even turn the proxyConnection into a stub temporarily by adding a return value to the proxy via the mock.addReturnValue(...). When the proxyConnection sees a return value it will return that instead of forwarding the call to the realConnection. Once all return values have been returned the proxyConnection will continue forwarding the method calls to the realConnection instance. That way you can switch between using the proxyConnection as a real connection or a stub. Smart, isn't?
It is not just database connections that are useful to mock. Any collaborator of a tested unit can potentially be mocked during testing. Whether to test a unit using a mock or a real collaborator depends on the situation. Proxies make it possible to do both at the same time, and even stub some method calls along the way. For more information about mock testing with Testimonial, see the Testimonial project page.
Stub, Mock and Proxy Testing的更多相关文章
- TDD学习笔记【六】一Unit Test - Stub, Mock, Fake 简介
这篇文章简介一下,如何通过 mock framework,来辅助我们更便利地模拟目标对象的依赖对象,而不必手工敲堆只为了这次测试而存在的辅助类型. 而模拟目标对象的部分,常见的有 stub objec ...
- Rails 5 Test Prescriptions 第7章 double stub mock
https://relishapp.com/rspec/rspec-mocks/v/3-7/docs/basics/test-doubles 你有一个问题,如果想为程序添加一个信用卡程序用于自己挣钱. ...
- Stub和Mock的理解
我对Stub和Mock的理解 介绍 使用测试驱动开发大半年了,我还是对Stub和Mock的认识比较模糊,没有进行系统整理. 今天查阅了相关资料,觉得写得很不错,所以我试图在博文中对资料进行整理一下,再 ...
- [转]软件测试- 3 - Mock 和Stub的区别
由于一直没有完全搞明白Mock和Stub的区别,所以查了很多文章,而这一篇是做好的: http://yuan.iteye.com/blog/470418 尤其是8楼,Frostred的发言,描述地相当 ...
- android中Stub Proxy答疑
在上篇添加账户源码解析的博文中,我们发现功能是由AccountManager的mService成员来实现.而mService其实是AccountManagerService,如果对android系统有 ...
- [转载] google mock cookbook
原文: https://code.google.com/p/googlemock/wiki/CookBook Creating Mock Classes Mocking Private or Prot ...
- spring security+cas(cas proxy配置)
什么时候会用到代理proxy模式? 举一个例子:有两个应用App1和App2,它们都是受Cas服务器保护的,即请求它们时都需要通过Cas 服务器的认证.现在需要在App1中通过Http请求访问App2 ...
- Dubbo学习笔记-RPC扩展和本地Mock
1.Dubbo介绍 Dubbo,一个是一款高性能Java RPC框架.私以为有中文官方文档,就不再重复介绍了 2.RPC扩展-本地存根stub RPC扩展功能:提前效验参数,缓存调用结果,日志记录等等 ...
- Mockito鸡尾酒第一杯 单测Mock
鸡尾酒 Mockito是Java的单元测试Mock框架. 它的logo是一杯古巴最著名的鸡尾酒Mojito, Mojito鸡尾酒,源自古巴的哈瓦那,带有浓厚的加勒比海风情. 并不浓烈,但是喝一杯下去, ...
随机推荐
- P2324 [SCOI2005]骑士精神
题目描述 输入输出格式 输入格式: 第一行有一个正整数T(T<=10),表示一共有N组数据.接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位.两组数据之间没有空行. 输出格式 ...
- HDU - 2814 Visible Trees
题意: m*n(1<=m,n<=100000)的森林里,起始点在(1,1),某人从(0,0)点开始看,问能看到多少棵树. 题解: 求出1~x中的每个数与1~y的数中互质的数的总和.用素数筛 ...
- [poj] 3304 Segments || 判断线段相交
原题 给出n条线段,判断是否有一条直线与所有线段都有交点 若存在这样一条直线,那么一定存在一条至少过两个线段的端点的直线满足条件. 每次枚举两条线段的两个端点,确定一条直线,判断是否与其他线段都有交点 ...
- [bzoj] 1036 Count
原题 树链剖分板子题 树剖详解: #include<cstdio> #include<algorithm> typedef long long ll; #define N 30 ...
- 树(tree)
树(tree) 题目描述 小明正在研究一种砍树游戏.一开始在W列H行的方格上,每一个格子都长着一颗树,格子的行从北到南依次编号,格子的列从西到东依次编号. 小明会砍倒一些树,每砍倒一颗树,树会占据这个 ...
- 洛谷 P1463 [SDOI2005]反素数ant && codevs2912反素数
题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6 ...
- 狂K 线段树
想写好树剖~~线段树very important HDU 1166 敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536 ...
- 【CF1016F】Road Projects(贪心)
题意:给你一棵n 个节点的树,定义1到n的代价是1到 n节点间的最短路径的长度. 现在给你 m 组询问,让你添加一条边权为 w 的边(不与原图重复),求代价的最大值.询问之间相互独立. 1≤n,m≤3 ...
- vue elementui 递归 sidebar可伸缩侧边栏
最近在学习vue 做了一个可伸缩的 侧边栏 记录下 在很多管理系统都用到 管理系统一般都长的差不多 首先是收起时候 展开时候 首先是新建一个Layout.vue <template> &l ...
- Python’s super() considered super!
如果你没有被Python的super()惊愕过,那么要么是你不了解它的威力,要么就是你不知道如何高效地使用它. 有许多介绍super()的文章,这一篇与其它文章的不同之处在于: 提供了实例 阐述了它的 ...