Download - 敏捷开发中 的通过 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 的工作方式:
↘ 按指定接口创建代理对象
↘ 设定代理对象的预期行为
↘ 使用代理类对象进行工作
UserCode
InterfaceProxyObject
Talk is cheap, show me the code: - Linus Interface defination
public interface SomeInterface {
public abstract Integer getDate(UserInfo user);
}
Jmock exampleMock mock = new Mock(SomeInterface.class);
SomeInterface service = (SomeInterface)mock.proxy;
// code to crate and set the args
UserInfo user = new UserInfo();
// 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 工具 - Jmock 示例
Interface definationpublic interface SomeInterface {
public abstract Integer getDate(UserInfo user);
}
EasyMock exampleMockControl control = MockControl.createControl(SomeInterface.class);
SomeInterface service = (SomeInterface)control.getMock();
// code to crate and set the args
UserInfo user = new UserInfo();
// 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 工具 - EasyMock 示例
Interface definationpublic interface SomeInterface {
public abstract Integer getDate(UserInfo user);
}
Mockito exampleSomeInterface service = mock(SomeInterface.class);
// code to crate and set the args
UserInfo user = new UserInfo();
// 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 工具 - Mockito 示例
拉里 · 沃尔 ( 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 = new ClassPathXmlApplicationContext("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 呢( 一 )
UserCode Interface
ProxyObject RPC Service
Implement
File DB
Web UI
新 Mock 设计结构
Web Service
Mock Server
UserCode
InterfaceProxyObject
创建对象• 由 Spring 配置的 Bean 决定创建何种代理对象
使用对象• 由代理对象负责处理服务接口的方法调用
• 如果代码对象是真实对象时,则真实对象负责处理调用请求。• 当代理对象是 Mock 对象时, Mock 对象将调用 RPC 到 MockServer
处理调用• MockServer 查询数据库中的配置,给出可与方法参数相匹配值,并作返回给
调用方。
Mock Service 工作流程
返回值的问题?◦ Q :返回值是一个 Java 类的实例,如何存储呢 ?◦ Q :返回类型可能很复杂,如何查看与编辑呢 ?◦ A :编写一个可以查看和编辑的“对象编辑器”
匹配关系的问题?◦ Q :参数可有多个,还会有复杂的类,如何设置一个匹配
条件?◦ A :让“对象编辑器”也能够编辑参数,并选择一些项作
为条件。
新 Mock 要解决的两个问题
Mock Web UI -资源浏览
Mock Web UI -入参匹配
Mock Web UI -对象编辑器
支持原始类型及一些特殊类型◦泛型,数组, List, Set, Map
有许多可用于扩展的特性◦ @Display◦ @DisplayName◦ @DisplayValue◦ @Description◦ @DefaultValue◦ @Readonly◦ @Converter◦ @Editor, @Editor.KeyEditor, ◦ @Descriptor
作为单独的项目开源
关于对象编辑器- PropertyGrid
Spring.xml<bean id="userSyncService“ class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean" >
<property name="interfaceName" value="com.ali.luna.sync.service.UserSyncService" />
<property name="version" value="1.0.0.1.mock" />
</bean>
Java codeApplicationContext context = new ClassPathXmlApplicationContext("SimbaCallService.xml");
UserSyncService userSyncService = (UserSyncService) context.getBean("userSyncService");
UserSyncObject user = new UserSyncObject();
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
开发其它更多的功能◦模拟服务器异常◦ ……
开源的准备
Mock 的未来
一淘测试网站: 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
关于我们-一淘测试工具组