JUnit学习笔记8---mock object进行独立测试2
来源:互联网 发布:json get post 编辑:程序博客网 时间:2024/04/20 23:21
使用mock objects,重构将变得容易!
有些人说过,单元测试应该对测试中的代码透明:你不应为了简化测试而改变运行时的代码。这是错误的!单元测试是对运行时代码最好的运用。应该同其他运用同等的看待。如果你的代码不能在测试中运用,你应该纠正代码。
例如,你看下面的代码怎样?
[...] import java.util.PropertyResourceBundle; import java.util.ResourceBundle;; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; [...] public class DefaultAccountManager implements AccountManager{ private static final Log LOGGER= LogFactory.getLog(AccountManager.class); public Account findAccountForUser(String userId){ LOGGER.debug("Getting account for user ["+userId+"]"); ResourceBundle bundle= PropertyResourceBundle.getBundle("technical"); String sql=bundle.getString("FIND_ACCOUNT_FOR_USER");// Some code logic to load a user account using JDBC [...] } }
用LogFactory取得一个Log对象。用PropertyResourceBundle获得了SQL命令。
你觉得这个代码看起来很好么?我们可以透过这个代码看见两个问题!它们都是同代码的适应性和承受力相关的。第一个问题是,你无法使用一个不同
的Log对象,因为这是由类内部创建的。一般来说,像这样的类应该能使用给定的任何Log,但是不行,做不到!第二个问题,就是PropertyResourceBundl
e。它看上去不错,但是,就是它决定了实现的方式,假使我们想用XML存储配置,就被这个类束缚了!再一次的,不应该由这个类决定使用何种实现,一个有
效的设计策略是,对象不应限制在其现有商业逻辑之外的可传入的对象。外围对象的选择应该能由在更高调用链上的某个人控制。随着调用层的上升,决定使
用哪个特定的记录器或是配置可以在最高层决定。这种策略最大化的提供了代码的灵活性。我们知道唯一不变的就是变化!重构所有的代码以传递领域对象是件费时的事。也许你不准备重构整个程序,而仅仅是为了一个单元测试,幸运的是这里有方便的重构技术,让你的代码保持相同的接口,并传递给它没有创建的域对象。让我们看看重构后的DefaultAccountManager类是什么样的!
[...] import java.util.PropertyResourceBundle; import java.util.ResourceBundle;; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; [...] public class DefaultAccountManager implements AccountManager{private Log logger;private Configuration configuration;public DefaultAccountManager(){ this.LogFactory.getLog(DefaultAccountManager.class),new DefaultConfiguration("technical")); }public DefaultAccountManager(Log logger, Configuration configuration){ this.logger=logger; this.configuration=configuration; }public Account findAccountForUser(String userId){this.logger.debug("Getting account for user["+userId+"]");this.configuration.getSQL("FIND_ACCOUNT_FOR_USER");}}
注意到,它使用了一个全新的Configuration接口,替换了前一个代码上的PropertyResourceBundle类。由于引入了一个接口(这很容易mock),同
时Configuration接口可以实现你想要的任何东西,这就使得代码变得灵活!你可以用Log和Configuration接口实现任何的实现复用DefaultAccountMan
ager类。这个设计变得更加的优秀了。类可以由外围(它的调用者)控制,同时你并没有破坏已有的接口,因为你只是添加了一个新的构造函数,同时还保留
了原有的构造函数,它仍然对logger和configuration进行初始化,赋给成员默认值。
重构提供了在测试中控制领域对象的一个暗门。在保留向后兼容性的同时,也重构了一条通向未来的路!
对于引入暗门使你的代码更加的容易测试,这让很多人担心,那么看看大名鼎鼎的极限编程专家是怎么说的:
我的车里有一个诊断器和一个测油汁。在炉子的上面和两个侧面都有一个检查孔。我的笔筒是透明的,所以没有墨水,我就可以看见。
如果我发现在类中有必要添加以个方法,使我能测试它,我也会去做。这经常发生,比如有着简单的接口和复杂的内部函数类可能需要一个
Extract Class重构。我只是把我理解的类的需求给予类,同时关注它下一步需要什么。
允许灵活的代码
我们在前面描述了一个设计模式称为控制反转(IOC)的著名模式。主要的想法是从类/方法之外实例化所有的
领域对象,同时传递各种参数。对象实例是传递给类的(通常通过接口),而不是由类来创建对象实例。在上面的例子中,这表现在把Log和Configuration对像传递给DefaultAccountManager类。DefaultAccountManager没有表明传递了哪些实例以及他们是如何构造的。只知道Log和Configuration的接口。
IOC使单元测试变得简单,为了证明这点,让我们看看你可以多么简单的进行findAccountByUser测试!
public void testFindAccountByUser(){ MockLog logger=new MockLog(); MockConfiguration Configuration=new MockConfiguration(); Configuration.setSQL("SELECT*[...]"); DefaultAccountManager am= new DefaultAccountManager(logger,configuration); Account account=am.findAccountForUser("1234"); // Perform asserts here [...] }
- JUnit学习笔记8---mock object进行独立测试2
- JUnit学习笔记8---mock object进行独立测试2
- JUnit学习笔记9---mock object进行孤立测试3
- JUnit学习笔记10---mock object进行孤立测试4
- JUnit学习笔记10---mock object进行孤立测试4
- JUnit学习笔记9---mock object进行孤立测试3
- JUnit学习笔记7---mock objects进行孤立测试1
- JUnit学习笔记7---mock objects进行孤立测试1
- junit--用mock object进行隔离测试(上)
- junit--用mock object进行隔离测试(二)
- junit---用mock object进行隔离测试(下)
- 使用Mock Object进行测试
- 使用Mock Object进行测试
- 使用Mock Object进行测试
- 使用Mock Object进行测试
- 使用junit+mockito进行mock测试实例
- [原创]用Mock Object进行独立单元测试(Testing in isolation with mock objects)
- (转)用Mock Object进行独立单元测试(Testing in isolation with mock objects)
- 图片驱动的计算机技术——Sikuli from MIT
- Ubuntu的安装
- JOIN ON后面的过滤条件和where后面的过滤条件有什么不同?
- cmd 命令符
- 最伤害孩子的十句话!
- JUnit学习笔记8---mock object进行独立测试2
- 二次开发: discuz7 弹出窗口技术详解
- Static详解
- 测试
- 大家好
- NULL和NUL的区别
- GNU 库通用公共许可证
- 关于QMatrix
- 时间的轨迹