問題描述
我想模擬一個 ResultSet.嚴重地.我正在重構(gòu)一大段復(fù)雜的代碼,它正在解析來自 ResultSet 的數(shù)據(jù),并且我希望我的代碼具有相同的行為.所以,我需要為正在重構(gòu)的部分編寫一個單元測試,以便能夠?qū)Υ诉M行測試.
I want to mock a ResultSet. Seriously. I'm refactoring one big complicated piece of code which is parsing data from ResultSet, and I want my code to behave identically. So, I need to write a unit test for the piece being refactored to be able to test this.
谷歌搜索后,我想出了兩個想法:
After googling I came up with 2 ideas:
- 使用 EasyMock,編寫 looooong 模擬序列.非常糟糕的解決方案:難以添加初始數(shù)據(jù)、難以更改數(shù)據(jù)、大量的測試調(diào)試.
- 使用 Apache Derby 或 HSQLDB 創(chuàng)建內(nèi)存數(shù)據(jù)庫,從文件或字符串?dāng)?shù)??組中填充它,使用一些神奇的 InMemoryDBUtils.query(sql) 進行查詢.然后使用該結(jié)果集.不幸的是,我沒有找到任何神奇的 InMemoryDBUtils 來快速編寫測試:-).IBM 文章使用 Derby 對持久性進行隔離單元測試"似乎正好滿足了我的需求,不過......
第二種方法看起來更簡單,更容易支持.
Second approach looks somewhat easier and much more supportable.
對于創(chuàng)建這樣的模擬,您有什么建議?(盡管有醫(yī)生,當(dāng)然:-)?我錯過了眉毛一些靈丹妙藥嗎?可能,DBUnit 就是這個工具?
What would you advice for creating such a mock? (despite doctors, of course :-)? Am I missing an eyebrow some silver bullet? Possibly, DBUnit is the tool for this?
推薦答案
據(jù)我所知,DBUnit 不提供結(jié)果集,盡管它可以很好地幫助您填充內(nèi)存數(shù)據(jù)庫.
DBUnit doesn't present a result set, to my knowledge, although it will well help you populate your in memory database.
我會說在這一點上模擬框架是錯誤的方法.模擬是關(guān)于測試行為和交互,而不僅僅是返回數(shù)據(jù),因此它可能會妨礙您.
I would say that a mocking framework is the wrong approach at this point. Mocking is about testing behavior and interaction, not just returning data, so it will likely get in your way.
我會改為實現(xiàn)一個結(jié)果集接口,或者創(chuàng)建一個結(jié)果集接口的動態(tài)代理到一個實現(xiàn)您關(guān)心的方法的類,而不必實現(xiàn)整個結(jié)果集.您可能會發(fā)現(xiàn)維護一個類就像維護一個內(nèi)存數(shù)據(jù)庫一樣容易(前提是被測數(shù)據(jù)集是一致的),而且可能更容易調(diào)試.
I would instead either implement a result set interface, or create a dynamic proxy of a result set interface to a class that implements the methods you care about without having to implement the whole result set. You will likely find maintaining a class as easy as maintaining an in memory database (provided that the dataset under test is consistent), and probably easier to debug.
您可以使用 DBUnit 備份該類,在其中使用 dbunit 拍攝結(jié)果集的快照,并讓 dbunit 在測試期間從 xml 讀取它,并讓您的虛擬結(jié)果集從 dbunit 的類中讀取數(shù)據(jù).如果數(shù)據(jù)稍微復(fù)雜,這將是一種合理的方法.
You could back up that class with DBUnit, where you take a snapshot of your result set with dbunit, and have dbunit read it back during the test from xml, and have your dummy result set read the data from dbunit's classes. This would be a reasonable approach if the data was mildly complex.
如果類是如此耦合以至于它們需要讀取作為同一測試的一部分而修改的數(shù)據(jù),我會選擇內(nèi)存數(shù)據(jù)庫.即便如此,我還是會考慮使用真實數(shù)據(jù)庫的副本,直到您設(shè)法分離該依賴項.
I would go for the in memory database if the classes were so coupled that they need to read data that was modified as part of the same test. Even then, I would consider using a copy of the real database until you managed to pull that dependency apart.
一個簡單的代理生成方法:
A simple proxy generation method:
private static class SimpleInvocationHandler implements InvocationHandler {
private Object invokee;
public SimpleInvocationHandler(Object invokee) {
this.invokee = invokee;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
if (!method.isAccessible()) {
method.setAccessible(true);
}
try {
return method.invoke(invokee, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
public static <T> T generateProxy(Object realObject, Class... interfaces) {
return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}
這篇關(guān)于用數(shù)據(jù)填充 ResultSet 的簡單方法的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!