MockServer的测试思想与实现(上篇)

上一篇 / 下一篇  2012-10-12 14:40:28 / 个人分类:杂谈

v'IlO!]T6}Vi] l0  背景

r~%~Nj0

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

Ct'e3P{'_2qL051Testing软件测试网5ZTNC#X6p

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

ci)] B j-g { q0  什么是MOCK51Testing软件测试网.C/{{ d(?H4~e)@"?

:g"H S.rm zfv0  Mock原本是一种在单测中使用的测试技术。51Testing软件测试网x\ L&["\zQO

2sAAlHt0  Mock的定义

T@1Y'zA9bD$Ja051Testing软件测试网fe8I VX2ja,L

   “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则像是一些桩。51Testing软件测试网2rO%]4a h

`,Y1Ja0Sl}s7gI h0  Mock框架简介51Testing软件测试网 @`\2[n yp

5nV5t/_}e0  在实际使用中,自己从头实现一个Mock对象是件繁琐的工作,而且经常出现各种低级错误,影响实际使用的效果。所以一些通用的Mock框架应运而生。如 “EasyMock”、“GMock”等。51Testing软件测试网p%g'Q7{.{ e Q

51Testing软件测试网(j*r.u @'WY,f

  “Hand-writing classes for Mock Objects is not needed.51Testing软件测试网 ^)G(X_td

51Testing软件测试网&p/pzEw.g;E7O

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

$BIr&{,m.x051Testing软件测试网!jP;\7~+s

  Supports return values and exceptions.

mx lX%T}0zg051Testing软件测试网K S4]9qM r4v

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

&w$xnx(\ s8q051Testing软件测试网P5Cn X(k ~-c

  上面是EasyMock文档中提到的Mock框架带来的几点好处,总结一下就是:可以使用一种非常简洁的方式描述对象的行为,而不需要真的去实现它。51Testing软件测试网)~FD)Q8g acw\XH

51Testing软件测试网i4]a }U0O#c

  关于EasyMock的详细信息,可以参考 EasyMock的使用文档51Testing软件测试网5?.xbn:z5Z'd}

51Testing软件测试网,x{Z_'I4\~0n

  Mock在单测中的应用

*n*K\U.DE.t]-i0

]"^A&R,mbNr0  使用Mock进行单测,大体上有以下几个方面(摘自EasyMock官方文档)

X ~k q-~0

P8V q{|@ P QL(e0  Define Interface

a`+CtNkD)o051Testing软件测试网L nT3c!gh)W]

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

z\:[{F xm \0

3XE#FL:?,j0  Define a Model Class51Testing软件测试网5av5f0dOjm*c:C

$HrV}x&@!i0   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) { // … } }

5]^1{/_9GO051Testing软件测试网$[b8L T Pbe c8W6a

  Create a Mock Object

;I-uFI ~(@t n0

K8].~)AYP2@*c-~0   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“);}

-l7B | jr&P|,wk0

Imj&o{+p0  Adding Behavior51Testing软件测试网$M%W!c5h"W3w5|

51Testing软件测试网5LKh%RW(U2EP

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

]'g"~+l2l a| N051Testing软件测试网 v9E{2w7R-oLQ VQ.{KK

  Specifying Return Values51Testing软件测试网+g3YRW QsH

51Testing软件测试网 Kn'cP-^+m,?3V8U;Sj TM*t

  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);}51Testing软件测试网$wB8Bl3Ko

H d T+[ |0  什么是Mock Server

$Z]`hl:a051Testing软件测试网G:i%yY B2^2i

  前面说了好多什么是Mock,或者说什么是Mock Object,那什么是Mock Server呢?其实它相对于我们一直使用的桩程序来说的,为了方便,下文将其称为Stub Server。51Testing软件测试网 Y%~;`9F*i

nB!ZH4}*U0  MockServer的工作原理

/b~Tj~[;h051Testing软件测试网 ?;|M O8Hy

  一般桩程序的结构

/?m"L#K7jHH0

/m_M9~ p0YK%gJ0  首先,我们先回顾一下以往的Stub Server是什么样的51Testing软件测试网SZi'R(o+j.kk)m8C

51Testing软件测试网DzZZ+T8SK

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

51Testing软件测试网#ni.P/DW+Qf t%B.}"h!w

  对于一个标准的Stub Server,它的结构通常是:51Testing软件测试网/j8ZM z9mLf

h @JSU],f4M0  创建SOCKET,监听所需的端口WHILE NOT STOP: 从socket中读数据 IF 数据满足[条件] THEN 返回[结果数据] END IFEND WHILE

U)]Oi3tV U-{051Testing软件测试网kX Fl&M1\

  为了适应的不同的被测系统,Stub Server需要跟据情况实现不同的接口协议,对数据包进行解析和封装,这部分的工作量占据了很大一部分比重,且实际代码往往单调繁琐。 这个问题可以利用一些代码自动生成技术或接口定义语言来解决,这方面的话题不在本文中讨论了。51Testing软件测试网Z d9bZV9y

:J8@I6w-u,O1W5@U,r0  接口实现好了,接下就是跟据需要来返回相应的数据了,对应于前面的流程,其实就是替换其中的[条件]和[结果数据],以适应不同的CASE。那 么如何描述 [条件]和[结果数据]自然也就是成了接下来要解决的问题,有时我们会直接将它们硬编码到程序里,或者使用配置文件来描述[条件]和[结果数据]以触发程 序中不同的处理代码。如果数据的结构比较简单,这种方法是很好实现的,但如果数据结构比较复杂,那配置文件格式的设计与数据的解析加载都会是件很烦人的事 情,而如果想在配置中添加一些简单的逻辑以使程序有更大的灵活性,则更是一件烦上加烦的事情。51Testing软件测试网&y`"\{ oGT;T

3Oe\slIG0  MockServer的结构

U1N*Im.a0

`k j#Qd@ D0  MockServer的设计思想在于将接口的操作和数据的操作分离,在实现桩程序时,只考虑对各种通信接口的包装,而将[条件]和[结果数据] 的构造交给使用者。这样,同样一个桩程序,只要是基于相同的通信协议,就可以模拟出任意的行为,就像mock对象可以模拟任意对象的行为一样。51Testing软件测试网L |3eqj

51Testing软件测试网y y%vg8kP9p |

  比如一个基于socket的Mock Server的可以描述为:51Testing软件测试网q3t;Pdw5J

51Testing软件测试网6F!q2F;?(n'O

  创建SOCKET,监听所需的端口WHILE NOT STOP: 从socket中读数据 执行[MOCK行为] END IFEND WHILE

Y k(`4@$m0

e4BB&Y [2lwn9}0  其中MOCK行为可能是这样描述的:51Testing软件测试网y*P CX iv&d

51Testing软件测试网,s)\$uA0Vw ~R

  ON: recieve(‘HELLO‘)DO: sendback(‘WORLD‘) keep_alive()ON: recieve(‘QUIT‘)DO: close_link()51Testing软件测试网~ ~ ?f ^

51Testing软件测试网fn]%_ K

  可见,Mock Server的核心就是如果实现执行[MOCK行为]

#K:U*z:y/g K1w}0

TAG:

 

评分:0

我来说两句

Open Toolbar