mock object 测试 模拟对象

术语

Tested Object – 被测对象

Mock – 假的 or 仿制的对象

 

What is Mock Object?

在讨论中我大致了解到 Mock Object 一般是用来做辅助单元测试,它负责隔离 Tested Object 与真实环境中模块或实体 (Real world object) 的交互,并“替代” or “ 冒充 这些真实模块或实体与 Tested Object 进行交互。

在“ JUnit in action ”这本书中关于 Mock Object 的描述如下:

A mock object (or mock for short) is an object created to stand in for an object that your code will be collaborating with. Your code can call methods on the mock object, which will deliver results as set up by your tests.

 

Mock Object 给我带来什么好处?

 

看看下面的图:

|-----------------------------------------------------------------|

|                                                                                         |                   

|      |---------------------|                                                   |             |-----------------------------|

|      |   Tested             | <------------------------------------------ à   | External Mock Object |

|      |      Object            |                                                      |             |----------------------------|

|      |---------------------|                                                 |

|                   /|/                 |--------------------|                       |

|                    |------- |  Internal Mock     |                       |

|                                     |     Object            |                       |

|                                     |--------------------|                    |

|      [Your system scope]                                                   |

|--------------------------------------------------------- -------- |

 

在测试你的 Tested Object 时,你可能会与你系统内的某个模块或系统外某个实体交互,而这些模块或实体在你做单元测试的时候可能并不存在,这时:

Ø         Internal Mock Object 可能是一个你的系统尚未完成的模块的“替身” (replacement)

Ø         External Mock Object 可能是测试你的 Tested Object 时需要的外部的环境实体的“替身”( replacement )。

不知道这样给 Mock Object 分类是否正确 J

 

我们来看看与 Real world object 交互有什么不足之处:

Ø         Real world object 的行为具有不确定性,我们难于控制它们的输出 or 返回结果。

Ø         Real world object 有些时候是难于被建立的或者说是无法获得的。

Ø         Real world object 的有些行为难于被触发,如磁盘已满,网络 error 等。

Ø         Real world object 可能不存在,比如你的 Tested Object 需要与你的系统的另一个 module 交互,而另一个 module 尚未开发完毕。

 

当然还不止这些,我们仅仅是列出一部分。

 

使用 Mock Object 替代 Real world object 后我们就会解决上述问题,换句话说当上面的情况出现后,我们就可以使用 Mock Object 。这也是什么时候该使用 Mock Object answer

Mock Object 是我们自己编写的,我们拥有控制它的绝对的权力,我们可以定制它的行为和输出。

 

Use Mock Object

使用 Mock Object 解决上述问题可分三步走:

 

1. Use an interface to describe the object

2. Implement the interface for production code

3. Implement the interface in a mock object for testing [3]

还有一点就是对于 Internal Mock Object 早晚你要实现出其 Real world object 的,因为那是你系统的一部分。

 

一个改自资料 [3] 的例子

public interface Environmental {

public long getTime();

// Other methods omitted...

}

对于这样一个接口,我们提供两种实现 ,

//real world object

public class SystemEnvironment implements Environmental {

public long getTime() {

return System.currentTimeMillis();

}

// other methods ...

}

 

//mock object

public class MockSystemEnvironment implements Environmental {

public long getTime() {

return currentTime;

}

public void setTime(Time aTime){

         this.currentTime = aTime;

}

private Time currentTime;

//others

}

我们可以看到在 MockSystemEnvironment 中我们提供“ setTime ”函数是为了提供控制 Mock Object 的接口。

 

我们要测试的类

//TestedObject

public class TestedObject{

         private Environmental env;

         TestedObject(Environmental aEnv){

                   this.env = aEnv;

}

public boolean isAm(){

         Calendar cal = Calendar.getInstance();

cal.setTimeInMillis(env.getTime());

int hour = cal.get(Calendar.HOUR_OF_DAY);

         if (hour <=12) return true;

         return false;

}

}

 

将要测试的类放入单元测试框架

public class TestTestedObject extends TestCase {

         public void testIsAm(){

                   MockSystemEnvironment env = new MockSystemEnvironment();

                   // Set up a target test time

Calendar cal = Calendar.getInstance();

cal.set(Calendar.YEAR, 2004);

cal.set(Calendar.MONTH, 10);

cal.set(Calendar.DAY_OF_MONTH, 1);

cal.set(Calendar.HOUR_OF_DAY, 16);

cal.set(Calendar.MINUTE, 55);

long t1 = cal.getTimeInMillis();

env.setTime(t1);

 

                   TestedObject to = new TestedObject(env);

                   assertFalse(to.isAm());

}

}

在该单元测试中我们使用了 Mock Object, 并且在使用前我们利用 setTime 接口,输入了我们需要的值。结果我们会通过测试。如果我们使用 Real Object ,我们得到的测试结果将是不固定的,后者可不是所期望的。从这个例子中你也应该体会到 Mock object 的一些好处了。

 

如果我们总是手动写我们需要的 Mock Object ,那将是一个很大的工作量。现在业界有了 Mock Objects easy mock 等开源框架的支持,是我们编写 Mock object 变得越来越容易。

 

参考资料:

1 、《 Test-Driven Development – A practical guide

2 、《 JUnit in action

3 、《 Pragmatic Unit Testing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值