扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年9月30日
关键字:
在本页阅读全文(共3页)
让我们来看一下重要的几行:
? Mock messenger = mock(Messenger.class);
创建一个实现Messenger接口的伪对象。在产品代码中,我们会创建一个与MS, Rendezvous或类似需求通讯的实现。
?messenger.expects( once() ).method("sendMessage").with( eq(MESSAGE_TOPIC), eq(valueArray) );
告诉伪对象期望sendMessage()方法只被调用一次,包含两个值:消息主题和一组消息内容。
?Registry.put( "MESSENGER", messenger.proxy() );
注册接口的伪实现。在这里,所有获取来自注册表中Messenger的代码会得到我们刚才创建的伪对象。
?Moose moose = new Moose(observationDate, MOOSE_AGE, null);
最后是我们的测试。我知道这看起来不像是个测试,但在他运行后,会运行tearDown()和调用super.tearDown()。在那个方法中会检查是否所有期望被满足,否则测试失败。因此如果sendMessage()方法没有调用我们的伪消息器,消息就会失败。
数据库测试
我知道你可能会想:“与LDAP和消息通讯的确不错,但在实际中,我们通常需要与数据库通讯。”是的,就像我们第一个启发式测试中(通过接口分离外部依赖),让我们简单地用接口来隐藏数据库:
public interface StorageManager {
void save(Object objectToSave) throws StorageException;
}
将实现放在注册表中,而代码只需要这样写:
StorageManager storageManager = (StorageManager) Registry.get( Registry.STORAGE );
storageManager.save( myObject );
在这里我们会用StorageException来封装所有实现中的异常。
不管用Hibernat,JDO或者其他持久层实现,都很容易将你与JDBC分离开来。我知道为每一个创建的对象编写select/insert/update/delete是很无聊的。因此我们可以只写一个HibernateStorageManager来实现StorageManager并处理其他细节。(如果你必须手写JDBC,Mockrunner项目可能对你写单元测试有所帮助)
在我们的单元测试中,会创建一个StorageManager伪对象并期望save方法被正确的对象调用。下面的save()的测试方法:
public void testSave() throws StorageException {
// Create a mock Messenger than ignores any messages it gets
Mock messenger = mock(Messenger.class);
messenger.stubs().method("sendMessage");
Registry.put( Registry.MESSENGER, messenger.proxy() );
// Create the moose
Moose moose = new Moose(new Date(), MOOSE_AGE, null);
// Create a mock StorageManager and tell it what will happen when we save the moose
Mock storage = mock(StorageManager.class);
storage.expects( once() ).method("save").with( same(moose) );
Registry.put(Registry.STORAGE, storage.proxy());
// Test !
moose.save();
}
让我们来看一下重要部分。首先我们建立一个Messenger桩:
messenger.stubs().method("sendMessage");
Jmock拥有一次或多次激活的桩。如果桩没有被调用或者被多次调用测试也不会失败。从先前的部分我们知道如何创建一个Moose并通过Messenger接口来发送消息。这个行为与save()方法无关,我们不希望他影响我们的测试,因此创建一个桩。
下一步,我们创建测试的Moose对象并在伪对象StorageManager上设置我们的期望值:
storage.expects( once() ).method("save").with( same(moose) );
这个看起来很直观。我们期望save()方法被调用一次,而moose对象被作为参数。在内部,same()方法用==来比较对象。而前面使用的eq()方法会使用equals。
最后我们保存的Moose:
moose.save();
一旦测试完成,Junit会运行tearDown()方法来检查所有的期望值是否被满足,否则测试失败。这个测试确保我们在请求Moose保存自己的时候,他会将工作代理给StorageManager。
当我们实际的StorageManager实现时(如HibernateStorageManager),我们会编写集成测试来确保他正确工作。如果两到三个集成测试用例保证HibernateStorageManager正确工作,那么你所需要在你单元测试中检查的只胡对象需要正确地将保存工作代理给StorageManager。我们测试的保存并不会真正地保存。
小结
所有上面的测试用例可以从资源中下载,可阅读旁注“构建样例程序”来运行样例。
下面是我在本文中所关注的两个重点:
1、使用接口将你的代码与外部资源分离,就像母牛保护她的孩子。
2、使用jMock创建这些接口的伪实现。
这两个技巧会的用处就像单元测试的用处。就像驼鹿不能出汗因为他们庞大的身体而且热量会通过内脏的发酵过程发散出去,我们在测试中也不需要出汗。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。