從elasticsearch1.6.2版本開始,項目組就開始進行基于elasticsearch的應(yīng)用開發(fā)舔稀,然而對于這些應(yīng)用的單元測試則相對落后——在搭建的es測試集群上跑測試用例。其實斗塘,es本身提供了易于使用地基礎(chǔ)的集成測試能力呻拌。在開始es功能的集成測試前,建議閱讀es測試官方文檔
項目使用的版本是2.1.1屠阻,下面遇到的問題都是針對此版本的。
1.elasticsearch中的jarHell問題
解決方案是在測試源碼目錄src/test/java中添加org.elasticsearch.bootstrap.JarHell
類额各,源碼如下:
package org.elasticsearch.bootstrap;
import java.net.URL;
public class JarHell {
private JarHell() {}
public static void checkJarHell() throws Exception {}
public static void checkJarHell(URL urls[]) throws Exception {}
public static void checkVersionFormat(String targetVersion) {}
public static void checkJavaVersion(String resource, String targetVersion) {}
public static URL[] parseClassPath() {return new URL[]{};}
}
參考目錄:解決es2.1.1中jarHell問題
2.和EasyMock集成問題
進行單元測試時国觉,經(jīng)常使用mock對象,項目中主要使用的是EasyMock和PowerMock虾啦。
如果測試類是繼承自ESIntegTestCase進行繼承測試時麻诀,要注意,如果使用@Before或者@After標識傲醉,則參考LuceneTestCase類中關(guān)于此的描述
* For instance-level setup, use {@link Before} and {@link After} annotated
* methods. If you override either {@link #setUp()} or {@link #tearDown()} in
* your subclass, make sure you call <code>super.setUp()</code> and
* <code>super.tearDown()</code>. This is detected and enforced.
3.設(shè)置elasticsearch集群實例的shard和replica數(shù)
對于shard個數(shù)和備份個數(shù)的設(shè)置蝇闭,要重載方法。
@Override
protected int numberOfShards() {
return 1;
}
@Override
protected int numberOfReplicas() {
return 0;
}
4.給出elasticsearch集成測試的小例子
public class Alias {
private AliasType aliasType;
private MGIndex current;
public Alias(AliasType aliasType) {
this.aliasType = aliasType;
current = MGIndexFactory.get(aliasType.getPrefix());
}
//對于每個shard設(shè)置界限值
public boolean isNeedAdd(Client client) throws ClusterUnhealthException {
// Check shard doc
String index = current.getIndexName();
IndicesStatsResponse stats = client.admin().indices().prepareStats(index).execute().actionGet();
if (stats.getFailedShards() > 0) {
throw new ClusterUnhealthException("Get shards stats failed");
}
int docThreshold = current.getDocThreshold();
for (ShardStats st : stats.getShards()) {
String info = String.format("%s contains %d files which's threshold is %d", index,
st.getStats().getDocs().getCount(), docThreshold);
MGLogger.info(info);
if (st.getStats().getDocs().getCount() > docThreshold)
return true;
}
return false;
}
}
其測試函數(shù)如下:
public class AliasTest extends ESIntegTestCase{
Alias alias = null;
@Before
public void setUp() throws Exception {
super.setUp();
alias = new Alias(AliasType.ATTACHMENT);
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Override
protected int numberOfShards() {
return 1;
}
@Override
protected int numberOfReplicas() {
return 0;
}
@Test
public void testIsNeedAdd() throws Exception {
indexRandom(true, false,
client().prepareIndex("test", "type1", "1").setSource("field1", "王寧"),
client().prepareIndex("test", "type1", "2").setSource("field1", "個人電話"),
client().prepareIndex("test", "type1", "3").setSource("field1", "12")
);
refresh();
MGIndex mgIndexMock = EasyMock.createMock(MGIndex.class);
EasyMock.expect(mgIndexMock.getIndexName()).andReturn("test").times(2);
EasyMock.expect(mgIndexMock.getDocThreshold()).andReturn(5).times(2);
EasyMock.replay(mgIndexMock);
alias.setCurrent(mgIndexMock);
assertFalse(alias.isNeedAdd(client()));
indexRandom(true, false,
client().prepareIndex("test", "type1", "4").setSource("field1", "王寧"),
client().prepareIndex("test", "type1", "5").setSource("field1", "個人電話"),
client().prepareIndex("test", "type1", "6").setSource("field1", "12")
);
assertTrue(alias.isNeedAdd(client()));
EasyMock.verify(mgIndexMock);
}
}
測試用例AliasTest中硬毕,使用EasyMock來mock current對象呻引,通過繼承ESIntegTestCase來進行es功能的集成測試——構(gòu)筑一個只有一個shard無備份的集群,shard中文檔的個數(shù)大于5時吐咳,使得isNeedAdd的返回值為空逻悠。
5.PowerMock和ESIntegTestCase配合產(chǎn)生的問題
由于ESIntegTestCase的祖先LuceneTestCase使用@RunWith(RandomizedRunner.class)和PowerMock在mock static函數(shù)時,使用的@RunWith(PowerMockRunner.class)沖突韭脊,使用這種方法無法將es的集成測試和PowerMock mock static 函數(shù)的能力結(jié)合在一起童谒,嘗試了Bootstrap using a Junit Rule和Delegate to another JUnit Runner仍沒解決ESIntegTestCase和PowerMock融合的問題,記錄留待解決沪羔。