... foo.isSame(null); //set the argument match rule -- always match //no matter what parameter is given control.setMatcher(MockControl.ALWAYS_MATCHER); //define the behavior -- return true when call //isSame(). And this method is expected //to be called at least once. control.setReturnValue(true, 1); ...MockControl中有三个预定义的ArgumentsMatcher实例。MockControl.ALWAYS_MATCHER在匹配时始终返回真而不管给什么参数值。MockControl.EQUALS_MATCHER会为参数值数组的每一个元素调用equals()方法。MockControl.ARRAY_MATCHER与MockControl.EQUALS_MATCHER基本一致,除了他调用的是Arrays.equals()。当然,开发人员可以实现自己的ArgumentsMatcher。
然而自定义的ArgumentsMatcher有一个副作用是需要定义方法调用的输出参数值。
... //just to demonstrate the function //of out parameter value definition foo.add(new String[]{null, null}); //set the argument match rule -- always //match no matter what parameter given. //Also defined the value of out param. control.setMatcher(new ArgumentsMatcher() { public boolean matches(Object[] expected, Object[] actual) { ((StringBuffer)actual[0]) .append(actual[1]); return true; } }); //define the behavior of add(). //This method is expected to be called at //least once. control.setVoidCallable(true, 1); ...setDefaultMatcher()设置MockControl的缺省ArgumentsMatcher实例。如果没有特定的ArgumentsMatcher,缺省的ArgumentsMatcher会被使用。这个方法应该在任何方法调用行为定义前被调用。否则,会抛出AssertionFailedError异常。
//get mock control MockControl control = ...; //get mock object Foo foo = (Foo)control.getMock(); //set default ArgumentsMatcher control.setDefaultMatcher( MockControl.ALWAYS_MATCHER); //begin behavior definition foo.bar(10); control.setReturnValue("ok"); ...如果没有使用setDefaultMatcher(),MockControl.ARRAY_MATCHER就是缺省的ArgumentsMatcher。
一个例子
下面是一个在单元测试中演示Mocquer用法的例子,假设存在一个类FTPConnector。
package org.jingle.mocquer.sample;import java.io.IOException;import java.net.SocketException;import org.apache.commons.net.ftp.FTPClient;public class FTPConnector { //ftp server host name String hostName; //ftp server port number int port; //user name String user; //password String pass; public FTPConnector(String hostName, int port, String user, String pass) { this.hostName = hostName; this.port = port; this.user = user; this.pass = pass; } /** * Connect to the ftp server. * The max retry times is 3. * @return true if succeed */ public boolean connect() { boolean ret = false; FTPClient ftp = getFTPClient(); int times = 1; while ((times <= 3) && !ret) { try { ftp.connect(hostName, port); ret = ftp.login(user, pass); } catch (SocketException e) { } catch (IOException e) { } finally { times++; } } return ret; } /** * get the FTPClient instance * It seems that this method is a nonsense * at first glance. Actually, this method * is very important for unit test using * mock technology. * @return FTPClient instance */ protected FTPClient getFTPClient() { return new FTPClient(); }}connect()方法尝试连接FTP服务器并且登录。如果失败了,他可以尝试三次。如果操作成功返回真。否则返回假。这个类使用org.apache.commons.net.FTPClient来生成一个实际的连接。他有一个初看起来毫无用处的保护方法getFTPClient()。实际上这个方法对使用伪技术的单元测试是非常重要的。我会在稍后解释。
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/