扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年9月30日
关键字:
在本页阅读全文(共3页)
后面,我们会实现Ranger接口作为包含在最终产品中的PersonnelUnit代理。但现在,我们需要的是一个简单实现返回我们所需要名字的实现―记住我们是在测试Moose而不是Ranger.
这种我们通过硬编码或定义方法调用异常的简单实现方式被称为伪对象。伪对象是测试中经常需要的东西,目前有很多可用的类库供你选择。其中最好用的类库之一是jMock。他使用J2SE1.3中的动态代理使我们在运行时创建接口实现。
为了使用jMock,我们必须首先修改我们的测试类使用权其继承MockObjectTestCase,并且在setup()和teardown()中调用父类中的相应方法:
public class TestMoose extends MockObjectTestCase {
public void setUp() throws Exception {
super.setUp();
}
public void tearDown() throws Exception {
super.tearDown();
}
... the rest as before ...
使用jMock后,getObserverName()的测试就更简单了:
public void testObserverName() {
Mock rangerMock = mock(Ranger.class);
rangerMock.expects( once() ).method("getName").will( returnValue(RANGER_NAME) );
Moose moose = new Moose(new Date(), MOOSE_AGE, (Ranger) rangerMock.proxy() );
assertEquals("Moose did not report correct ranger", RANGER_NAME, moose.getObserverName() );
}
让我们逐行地解释一下:
?Mock rangerMock = mock(Ranger.class);
这行创建了一个Mock对象来伪装Ranger接口的实现,调用rangerMock.proxy()返回Ranger
?rangerMock.expects( once() ).method("getName").will( returnValue(RANGER_NAME) );
这里是最有趣的地方。他的用途很明显:告诉Mock期望getName()方法仅被调用一次,并且在被调用后应该返回RANGER_NAME的值。在测试的最后,当我们的tearDown()方法调用super.tearDown()时,我们的父类MockObjectTestCase会检查是否所有期望值都已经满足,否则就会失败。
? Moose moose = new Moose(new Date(), MOOSE_AGE, (Ranger) rangerMock.proxy() );
这行创建Moose对象。注意我们是如何获取Ranger的实现的,通过调用的Mock.proxy()方法。
?assertEquals("Moose did not report correct ranger", RANGER_NAME, moose.getObserverName() );
最后是测试本身。很容易吧。因为Ranger接口使用起来很方便,我们并不需要经常这样。
注册模式
驼鹿喜欢居住吃水池草,但他们也是别人的猎物。因为驼鹿与别的物种的关系,WOM要求我们在发现一只驼鹿的时候给其他的团队发送消息。这些消息将被熊/狼/鹿/水池草的保护人员获取。
在项目中的消息系统是一个企业级的服务系统,如Tibco Rendezvous, IBM MQSeries, 或JMS的实现。就像PersonnelUnit依赖LDAP服务器,这种消息系统的要求也使得测试变的困难。如何才能使这些对象在没有后台的服务系统时存在呢?我们又如何能得到一个这样的消息系统呢?开始的想法是在集成测试中处理,但实际上我们需要的是一个接口和相应的模式。
让我们用一个友好的接口来隐藏消息系统吧:
public interface Messenger {
void sendMessage(String topic, Object[] values);
}
现在是我们第二个启发式的单元测试:用接口标示服务或角色,因此他们的名字通常心or/er为结尾。
现在,我们需要的是如何获取一个Messenger的实现,这相对于寻找驼鹿来说简单多了。如果你使用IOC容器(如Spring或HiveMind),你已经知道容器会帮你处理Messenger实现。否则,使用注册模式(服务定位模式的一种),这是一种简单的全局静态图来映射服务名与其实现。
public class Registry {
private static Map registry = new HashMap();
public static void put(String key, Object implementation) {
registry.put(key, implementation);
}
public static Object get(String key) {
return registry.get(key);
}
}
在代码中,我们这样使用注册:
Messenger messenger = (Messenger) Registry.get("MESSENGER");
messenger.sendMessage(A_TOPIC, someValues);
跟着是测试用例:
public void testMessageIsSent() {
Date observationDate = new Date();
Object[] valueArray = new Object[] { observationDate, new Integer(MOOSE_AGE) };
Mock messenger = mock(Messenger.class);
messenger.expects( once() ).method("sendMessage").with( eq(MESSAGE_TOPIC), eq(valueArray) );
Registry.put( "MESSENGER", messenger.proxy() );
Moose moose = new Moose(observationDate, MOOSE_AGE, null );
}
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者