知识大全 轻松测试-学习如何简化测试外部资源

Posted 驼鹿

篇首语:孤独如影随形,我们不能杀死他,只能与他和解。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 轻松测试-学习如何简化测试外部资源相关的知识,希望对你有一定的参考价值。

  我们将从构建简单的驼鹿监视软件开始示例各种场景下的测试驱动开发   鹿是鹿家族中的最大个的成员 目前世界上估计有 百万头 为了更好的统计 世界驼鹿组织让我们开发一个驼鹿监视软件 希望保护人员能够跟踪和记录他们见到的驼鹿 本文假设读者已经熟悉java/ant/maven/classpath 而且至少写过一两个简单的junit测试 Vanilla JUnit首先编写Moose类 package moose;import java util Date;public class Moose     private Date dateTimeObserved;    private int age;        public Moose(Date dateTimeObservedParam int estimatedAge)         this dateTimeObserved = dateTimeObservedParam;        this age = estimatedAge;    

  虽然驼鹿最长可以生存 年 但大部分驼鹿在年青的时候就被捕杀 通常只活了 年 根据世界驼鹿组织报告 我们想知道某一年龄后的驼鹿数据 因此我们增加了isOlderThan(int)方法 单元测试如下     public void testIsOlderThan()         Moose moose = new Moose(new Date() MOOSE_AGE);                assertTrue( Moose age + MOOSE_AGE + should of been older than + TEST_AGE moose isOlderThan(TEST_AGE) );    方法:    boolean isOlderThan(int contenderAge)         return this age >= contenderAge;       这是一个普通的junit测试用例 这种方式通常用在测试驱动的开发中 这种完全独立的方法一般是很少的 通常我们都需要一些代价昂贵的或比较难构建的外部资源 使用伪对象和jMock  观察驼鹿的最佳时间是在黎明和黄昏 跟其他动物的观察时间相似 WOM希望我们提供获取记录驼鹿被发现的时间的保护人员 这样就可以通过String getObserverName()来获取相应的驼鹿了   不幸地是 保护人员的接口来自第三方接口PersonnelUnit 而这是个大家伙没有LDAP我们是无法构造的   为了测试getObserverName() 我们可以启动LDAP服务器 发送数据 运行测试用例 然后再关闭LDAP 但那将是集成测试 而不是单元测试了 对我们来说宁可多写些代码 因此 我们创建了一个包含我们需要方法的Ranger接口     public interface Ranger             String getName();          这给我们第一个启发式的单元测试 用接口分离外部依赖   我们需要改变Moose的构造函数增加Ranger参数 于是变成      above as before     private Ranger observer;        public Moose(   Date dateTimeObservedParam                     int estimatedAge                     Ranger observedBy)             this dateTimeObserved = dateTimeObservedParam;        this age = estimatedAge;        this observer = observedBy;         below as before

  后面 我们会实现Ranger接口作为包含在最终产品中的PersonnelUnit代理 但现在 我们需要的是一个简单实现返回我们所需要名字的实现—记住我们是在测试Moose而不是Ranger   这种我们通过硬编码或定义方法调用异常的简单实现方式被称为伪对象 伪对象是测试中经常需要的东西 目前有很多可用的类库供你选择 其中最好用的类库之一是jMock 他使用J SE 中的动态代理使我们在运行时创建接口实现   为了使用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() thod( 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() thod( 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() thod( sendMessage ) with( eq(MESSAGE_TOPIC) eq(valueArray) );            Registry put( MESSENGER messenger proxy() );                Moose moose = new Moose(observationDate MOOSE_AGE null );    

  让我们来看一下重要的几行 · Mock messenger = mock(Messenger class);创建一个实现Messenger接口的伪对象 在产品代码中 我们会创建一个与MS Rendezvous或类似需求通讯的实现 ·messenger expects( once() thod( 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(thod( 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() thod( save ) with( same(moose) );          Registry put(Registry STORAGE storage proxy());                    // Test !          moose save();        让我们来看一下重要部分 首先我们建立一个Messenger桩 messenger stubs(thod( sendMessage );

cha138/Article/program/Java/ky/201311/27956

相关参考

知识大全 利用spring2.5和Reflection简化测试中的mock[3]

利用spring2.5和Reflection简化测试中的mock[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

知识大全 利用spring2.5和Reflection简化测试中的mock[2]

利用spring2.5和Reflection简化测试中的mock[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

知识大全 利用spring2.5和Reflection简化测试中的mock[1]

利用spring2.5和Reflection简化测试中的mock[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

高压直流接地极对外部设施影响的测试规定有哪些?

  二锅头  1.高压直流接地极对外部设施的影响宜在接地极附近,通过对外部设施情况调研及实际测量的方法来确定。  2.对通信系统的干扰试验宜与邮电部门共同协商进行,测试结果需用统计方法处理,测试的目的

高压直流接地极对外部设施影响的测试规定有哪些?

  二锅头  1.高压直流接地极对外部设施的影响宜在接地极附近,通过对外部设施情况调研及实际测量的方法来确定。  2.对通信系统的干扰试验宜与邮电部门共同协商进行,测试结果需用统计方法处理,测试的目的

知识大全 struts2迭代不同对象的测试

  在平时使用s:iterator这个迭代标签一般我们都是把一个相同类型的多个对象放入一个集合当中那么是否可以放入不相同的对象来迭代呢?日常工作有时候可能是需要这样来简化程序的我今天测试了一下好像完全

知识大全 C#语言学习:C#数据报编程之测试程序

C#语言学习:C#数据报编程之测试程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  C#中自定

知识大全 人教版小学二年级下册数学期中测试A学习与评价题目

人教版小学二年级下册数学期中测试A学习与评价题目  以下文字资料是由(本站网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!人教版

知识大全 配置与测试PHP环境

PHPWeb开发学习实录:配置与测试PHP环境  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &

知识大全 数据结构[6]

  在线测试  因为研究生考试基本上是靠我们自己学习那么学习完之后如何知道学习的效果呢?这就需要多参加测试特别是在线测试会对我们有很大的帮助计算机考研专业课中有分的单项选择题这是与软考的考法一致的从考