MockServer的测试思想与实现

发表于:2014-06-11来源:百度质量部作者:不详点击数: 标签:软件测试
在Linux后台服务类模块测试中,经常会遇到被测模块需要通过socket接口调用其它模块的情况,多数时候,我们可以直接连接被调用的模块来进行测试。但有时这并不是个好主意,比如被

  背景

  在Linux后台服务类模块测试中,经常会遇到被测模块需要通过socket接口调用其它模块的情况,多数时候,我们可以直接连接被调用的模块来进行测试。但有时这并不是个好主意,比如被调用的模块部署成本很高、操作比较繁琐、数据构造困难、性能不够好等,更重要的是一些接口的异常情况可能根本无法直接模拟。

  所以在实际测试中,我们少不了要自己编写一些桩程序来模拟被调用模块的行为。而当我们写过几个桩程序后就会发现,所有的桩程序都大同小异,只是具体的接口协议不同而已,而像链接管理、配置管理、日志管理等工作,完全都是一样的。那么是否可以通过某种方式,将相同的部分抽离出来,构造一个桩程序时,只需要考虑接口的逻辑,是不是就可以节省许多重复的工作呢?

  什么是MOCK

  Mock原本是一种在单测中使用的测试技术。

  Mock的定义

  “Mock Objects simulate parts of the behavior of domain code, and are able to check whether they are used as defined. Domain classes can be tested in isolation by simulating their collaborators with Mock Objects.”。前面这段话摘自EasyMock的说明文档,简单来说单测CASE可以认为是一些驱动代码,而Mock Object则像是一些桩。

  Mock框架简介

  在实际使用中,自己从头实现一个Mock对象是件繁琐的工作,而且经常出现各种低级错误,影响实际使用的效果。所以一些通用的Mock框架应运而生。如 “EasyMock”、“GMock”等。

  “Hand-writing classes for Mock Objects is not needed.

  Supports refactoring-safe Mock Objects: test code will not break at runtime when renaming methods or reordering method parameters

  Supports return values and exceptions.

  Supports checking the order of method calls, for one or more Mock Objects. ”

  上面是EasyMock文档中提到的Mock框架带来的几点好处,总结一下就是:可以使用一种非常简洁的方式描述对象的行为,而不需要真的去实现它。

  关于EasyMock的详细信息,可以参考 EasyMock的使用文档

  Mock在单测中的应用

  使用Mock进行单测,大体上有以下几个方面(摘自EasyMock官方文档)

  Define Interface

  public interface Collaborator { void documentAdded(String title); void documentChanged(String title); void documentRemoved(String title); byte voteForRemoval(String title); byte[] voteForRemovals(String[] title); }

  Define a Model Class

  public class ClassUnderTest { // … public void addListener(Collaborator listener) { // … } public void addDocument(String title, byte[] document) { // … } public boolean removeDocument(String title) { // … } public boolean removeDocuments(String[] titles) { // … } }

  Create a Mock Object

  protected void setUp() { mock = createMock(Collaborator.class); // 1 classUnderTest = new ClassUnderTest(); classUnderTest.addListener(mock);} public void testRemoveNonExistingDocument() { // 2 (we do not expect anything) replay(mock); // 3 classUnderTest.removeDocument(“Does not exist“);}

  Adding Behavior

  public void testAddDocument() { mock.documentAdded(“New Document“); // 2 replay(mock); // 3 classUnderTest.addDocument(“New Document“, new byte[0]); }

  Specifying Return Values

  public void testVoteForRemoval() { mock.documentAdded(“Document“); // expect document addition // expect to be asked to vote for document removal, and vote for it expect(mock.voteForRemoval(“Document“)).andReturn((byte) 42); mock.documentRemoved(“Document“); // expect document removal replay(mock); classUnderTest.addDocument(“Document“, new byte[0]); assertTrue(classUnderTest.removeDocument(“Document“)); verify(mock);}

  什么是Mock Server

  前面说了好多什么是Mock,或者说什么是Mock Object,那什么是Mock Server呢?其实它相对于我们一直使用的桩程序来说的,为了方便,下文将其称为Stub Server。

  MockServer的工作原理

  一般桩程序的结构

  首先,我们先回顾一下以往的Stub Server是什么样的

  Stub Server,作为一个模拟下游模块的行为的程序,它的功能无非两方面,一个是接受请求,一个是返回结果。当然为测试的便利,在返回结果时可能还会有一些简单的逻辑,比如填充一些无关字段。

  对于一个标准的Stub Server,它的结构通常是:

原文转自:http://www.ltesting.net