230 likes | 541 Views
敏捷开发中 的通过 Mock 实践. 测 试工具-朱士松. Mock 与敏捷的关系 ( 一 ). 敏捷要求及早地对程序进行测试 Test First Development Test Driven Development 敏捷要求尽早交付有价值的软件 尽早交付需要以尽早完成前提 为加快速度通常会采取并行开发 并行开发中的服务依赖方难以测试. Mock 与敏捷的关系 ( 二 ). 并行开发造成的测试困难 依赖的服务仍在开发之中-无法获取和使用这项服务 依赖的服务处于调试阶段-不稳定的服务难以调查测试失败 使用真实服务有其它困难
E N D
敏捷开发中的通过Mock实践 测试工具-朱士松
Mock与敏捷的关系(一) • 敏捷要求及早地对程序进行测试 • Test First Development • Test Driven Development • 敏捷要求尽早交付有价值的软件 • 尽早交付需要以尽早完成前提 • 为加快速度通常会采取并行开发 • 并行开发中的服务依赖方难以测试
Mock与敏捷的关系(二) • 并行开发造成的测试困难 • 依赖的服务仍在开发之中-无法获取和使用这项服务 • 依赖的服务处于调试阶段-不稳定的服务难以调查测试失败 • 使用真实服务有其它困难 • 真实对象的行为难以触发-某些闹钟警报等触发条件很特殊 • 真实对象的行为结果难测-不便于编写短小有针对性的测试 • 异常处理测试需引发异常,但异常难以以某种方式稳定产生 • 压力测试时测试性能瓶颈
需要使用Mock对象 • 如果有个可控的虚拟对象? • 行为触发 • 控制结果 • 控制性能
流行的 Mock 工具 • Java • Jmock, Mockito, EasyMock • … • Mockrunner • .Net • Nmock, .NetMock • C/C++ • Google Mock -大多Mock的工作方式: • 按指定接口创建代理对象 • 设定代理对象的预期行为 • 使用代理类对象进行工作
流行的Mock工具- Jmock示例 • Talk is cheap, show me the code: - Linus • Interface defination publicinterfaceSomeInterface{ publicabstract Integer getDate(UserInfo user); } • Jmock example Mock mock=new Mock(SomeInterface.class); SomeInterface service =(SomeInterface)mock.proxy; // code to crate and set the args UserInfo user =newUserInfo(); // code to create and set the return value Integer[] expected =new Integer[]{1,2,3,4,5}; // code to set the funciton behavior mock.expects(once()).method("getDate").with(eq(args)).will(returnValue(expected); // work with the interface Integer[] actual =mock.getDate(user); assertArrayEquals(expected, actual);
流行的Mock工具-EasyMock示例 • Interface defination publicinterfaceSomeInterface{ publicabstract Integer getDate(UserInfo user); } • EasyMock example MockControl control = MockControl.createControl(SomeInterface.class); SomeInterface service = (SomeInterface)control.getMock(); // code to crate and set the args UserInfo user =newUserInfo(); // code to create and set the return value Integer[] expected =new Integer[]{1,2,3,4,5}; // code to set the funciton behavior EasyMock.expect(service.getDate(user)).andReturn(expected); EasyMock.replay(service); // work with the interface Integer[] actual =service.getDate(user); assertArrayEquals(expected, actual);
流行的Mock工具-Mockito示例 • Interface defination publicinterfaceSomeInterface{ publicabstract Integer getDate(UserInfo user); } • Mockito example SomeInterface service = mock(SomeInterface.class); // code to crate and set the args UserInfo user =newUserInfo(); // code to create and set the return value Integer[] expected =new Integer[]{1,2,3,4,5}; // code to set the funciton behavior when(service.getDate(user)).thenReturn(expected); Integer[] actual =service.getDate(user);
为什么还要再造一个 Mock呢(一) • 拉里·沃尔 (Perl 语言之父)的经典语录 • “Most of you are familiar with the virtues of a programmer. There are three, of course: laziness, impatience, and hubris.” • 你们大部分人都熟悉程序员的美德。当然了,是这三种:懒惰、急躁、傲慢。 • 现有Mock需要写
为什么还要再造一个 Mock呢(二) • “懒惰”又“急躁”的程序员希望能简单地完事: ApplicationContext context =newClassPathXmlApplicationContext("SpringServices.xml"); SomeService service =(SomeService)context.getBean("ServiceBeanId"); // wo don’t know where this service is real servie or mock service // method call on the interface, no more codes to set the exprected result by codes Integer[] array =service.getData("Monday"); // the other codes to use the array ...
为什么还要另做新的 Mock呢(一) • 现有Mock软件的一些不便 • 显式地使用了虚拟对象,测试真实对象时还要另写代码 • 显式设定了对象的行为,这段代码对于真实服务是多余的 • 设定预期的代码可能会很繁琐,比如入参和返回值很复杂 • 最重要的一点是,因为使用了Mock就需要要多写一套代码 • 我们更期待有一个这样的Mock • 隐式使用:让配置来决定是真实对象还是Mock对象在服务 • 数据驱动:数据决定行为,只需要造数据,不额外写代码 • API访问:仍然提供API,可以像其他Mock的方式一样工作
新Mock设计结构 Mock Server Web Service
新Mock 要解决的两个问题 • 返回值的问题? • Q :返回值是一个Java类的实例,如何存储呢? • Q :返回类型可能很复杂,如何查看与编辑呢? • A :编写一个可以查看和编辑的“对象编辑器” • 匹配关系的问题? • Q:参数可有多个,还会有复杂的类,如何设置一个匹配条件? • A:让“对象编辑器”也能够编辑参数,并选择一些项作为条件。
MockWebUI-服务管理 • http://10.232.134.38:8080/HsfServiceMock
关于对象编辑器-PropertyGrid • 支持原始类型及一些特殊类型 • 泛型,数组,List, Set, Map • 有许多可用于扩展的特性 • @Display • @DisplayName • @DisplayValue • @Description • @DefaultValue • @Readonly • @Converter • @Editor, @Editor.KeyEditor, • @Descriptor • 作为单独的项目开源
Mock的实际使用示例 • Spring.xml <beanid="userSyncService“class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean"> <propertyname="interfaceName"value="com.ali.luna.sync.service.UserSyncService"/> <propertyname="version"value="1.0.0.1.mock"/> </bean> • Javacode ApplicationContext context =newClassPathXmlApplicationContext("SimbaCallService.xml"); UserSyncServiceuserSyncService=(UserSyncService)context.getBean("userSyncService"); UserSyncObject user =newUserSyncObject(); user.setLocation(“suzou"); // more code to set this parameter try{ int ok =userSyncService.syncUser(user,"BP"); System.out.println(ok); } catch(Exception ex){ ex.printStackTrace(); }
Mock的适用场景 • 适用的场景 • 交互的对象是一个”Interface” • 调用的目的在于得到返回值 • 不适用的场景 • 不适宜模拟类似set/write等需要改变某种状态的行为 • 同样调用需要不同的返回值时,配置过程比较复杂 • 有些接口有专用的Mock工具(如servlet/filter/jdbc/jmc)
Mock的未来 • 向通用Mock的方向前进 • 用开放的RPC框架代替当前使用的HSF • 开发其它更多的功能 • 模拟服务器异常 • …… • 开源的准备
关于我们-一淘测试工具组 • 一淘测试网站: http://testing.etao.com/ • 一淘测试微博:http://weibo.com/etaotesting • Bug 管理软件:http://testing.etao.com/project/bugfree(BSD) • 任务调度系统:http://testing.etao.com/project/toast(GPL) • 关于本人: 淘锐奇 -http://weibo.com/treesong