Докато приемането на Apache HBase за изграждане на приложения за крайни потребители се е увеличило, много от тези приложения (и много приложения като цяло) не са добре тествани. В тази публикация ще научите някои от начините, по които това тестване може лесно да се извърши.
Ще започнем с модулно тестване чрез JUnit, след това ще преминем към използването на Mockito и Apache MRUnit и след това към използване на мини-клъстер HBase за тестване на интеграция. (Самата кодова база HBase се тества чрез мини-клъстер, така че защо да не се възползвате и от нея за приложения нагоре по веригата?)
Като основа за дискусия, нека приемем, че имате обект за достъп до данни HBase (DAO), който прави следното вмъкване в HBase. Логиката може да е по-сложна, разбира се, но за пример, това върши работа.
public class MyHBaseDAO { public static void insertRecord(HTableInterface table, HBaseTestObj obj) хвърля изключение { Put put =createPut(obj); таблица.поставя(поставя); } private static Put createPut(HBaseTestObj obj) { Поставете put =new Put(Bytes.toBytes(obj.getRowKey())); put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1"), Bytes.toBytes(obj.getData1())); put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2"), Bytes.toBytes(obj.getData2())); връщане пускане; }}
HBaseTestObj е основен обект с данни с гетери и сетери за rowkey, data1 и data2.
insertRecord прави вмъкване в таблицата HBase срещу семейството колони на CF, с CQ-1 и CQ-2 като квалификатори. Методът createPut просто попълва Put и го връща на извикващия метод.
Използване на JUnit
JUnit, който е добре познат на повечето Java разработчици в този момент, лесно се прилага към много HBase приложения. Първо добавете зависимостта към вашия pom:
junit junit 4.11 test
Сега, в рамките на тестовия клас:
public class TestMyHbaseDAOData { @Test public void testCreatePut() хвърля изключение { HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1("ДАННИ-1"); obj.setData2("ДАННИ-2"); Поставете put =MyHBaseDAO.createPut(obj); assertEquals(obj.getRowKey(), Bytes.toString(put.getRow())); assertEquals(obj.getData1(), Bytes.toString(put.get(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1")).get(0).getValue())); assertEquals(obj.getData2(), Bytes.toString(put.get(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2")).get(0).getValue())); } }
Това, което направихте тук, беше да гарантирате, че вашият метод createPut създава, попълва и връща обект Put с очаквани стойности.
Използване на Mockito
И така, как правите единично тестване на горния метод insertRecord? Един много ефективен подход е да го направите с Mockito.
Първо добавете Mockito като зависимост към вашия pom:
предварително> org.mockito mockito-all 1.9.5 тест
След това в тестов клас:
@RunWith(MockitoJUnitRunner.class) публичен клас TestMyHBaseDAO{ @Mock частна таблица на HTableInterface; @Mock частен HTablePool hTablePool; @Captor частен ArgumentCaptor putCaptor; @Test public void testInsertRecord() хвърля изключение { //връщане на макетна таблица, когато getTable се извика when(hTablePool.getTable("tablename")).thenReturn(table); //създайте тестов обект и извършете извикване към DAO, който се нуждае от тестване HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1("ДАННИ-1"); obj.setData2("ДАННИ-2"); MyHBaseDAO.insertRecord(таблица, obj); проверка(таблица).поставяне(putCaptor.capture()); Поставете put =putCaptor.getValue(); assertEquals(Bytes.toString(put.getRow()), obj.getRowKey()); assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1"))); assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2"))); assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),Bytes.toBytes("CQ-1")).get(0).getValue()), "DATA-1"); assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),Bytes.toBytes("CQ-2")).get(0).getValue()), "DATA-2"); }}
Тук сте попълнили HBaseTestObj с “ROWKEY-1”, “DATA-1”, “DATA-2” като стойности. След това използвахте подиграваната таблица и DAO, за да вмъкнете записа. Уловихте Put, което DAO би вмъкнал и проверихте, че rowkey, data1 и data2 са това, което очаквате да бъдат.
Ключът тук е да управлявате пула на htable и създаването на екземпляр на htable извън DAO. Това ви позволява да ги подигравате чисто и да тествате Puts, както е показано по-горе. По подобен начин вече можете да разширите във всички други операции, като получаване, сканиране, изтриване и т.н.
Използване на MRUnit
С покрито редовно тестване на единици за достъп до данни, нека се обърнем към задания на MapReduce, които са в противоречие с таблици HBase.
Тестването на MR задачи, които противоречат на HBase, е толкова лесно, колкото тестването на обикновени задания на MapReduce. MRUnit улеснява тестването на задания на MapReduce, включително тези на HBase.
Представете си, че имате MR работа, която записва в таблица на HBase, „MyTest“, която има едно семейство колони, „CF“. Редукторът на такава работа може да изглежда така:
public class MyReducer extends TableReducer{ public static final byte[] CF ="CF".getBytes(); публичен статичен краен байт[] QUALIFIER ="CQ-1".getBytes(); public void reduce(Text key, Iterable values, Context context) хвърля IOException, InterruptedException { //куп от обработка за извличане на данни, които да бъдат вмъкнати, в нашия случай, нека да кажем, че просто //прибавяме всички записи, които получаваме от мапера за този конкретен //ключ и вмъкнете един запис в HBase StringBuffer data =new StringBuffer(); Поставете put =new Put(Bytes.toBytes(key.toString())); for (Текст val :стойности) { data =data.append(val); } put.add(CF, QUALIFIER, Bytes.toBytes(data.toString())); //запис в HBase context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())), put); } }
А сега как ще тествате горния редуктор в MRUnit? Първо, добавете MRUnit като зависимост към вашия pom.
предварително> org.apache.mrunit mrunit 1.0.0 тест
След това, в рамките на тестовия клас, използвайте ReduceDriver, който MRUnit предоставя, както следва:
public class MyReducerTest { ReduceDriverreduceDriver; байт[] CF ="CF".getBytes(); byte[] QUALIFIER ="CQ-1".getBytes(); @Преди public void setUp() { MyReducer reducer =new MyReducer(); reduceDriver =ReduceDriver.newReduceDriver(редуктор); } @Test public void testHBaseInsert() хвърля IOException { String strKey ="RowKey-1", strValue ="DATA", strValue1 ="DATA1", strValue2 ="DATA2"; List list =new ArrayList (); list.add(нов текст(strValue)); list.add(нов текст(strValue1)); list.add(нов текст(strValue2)); //тъй като в нашия случай всичко, което редукторът прави, е добавяне на записите, които картографът //изпраща, трябва да получим следното обратно String expectOutput =strValue + strValue1 + strValue2; //Вход за настройка, имитиране на това, което картографът би предал //на редуктора и стартирайте тест reduceDriver.withInput(new Text(strKey), list); //изпълняваме редуктора и получаваме неговия изход List > result =reduceDriver.run(); //извличане на ключа от резултата и проверка assertEquals(Bytes.toString(result.get(0).getFirst().get()), strKey); //извличане на стойност за CF/QUALIFIER и проверка Поставете a =(Put)result.get(0).getSecond(); Низ c =Bytes.toString(a.get(CF, QUALIFIER).get(0).getValue()); assertEquals(очакванИзход,c); }}
По принцип, след куп обработка в MyReducer, вие потвърдихте, че:
- Резултатът е това, което очаквате.
- Put, който е вмъкнат в HBase, има „RowKey-1“ като rowkey.
- „DATADATA1DATA2“ е стойността за фамилията CF колони и квалификатора на CQ колони.
Можете също да тествате Mappers, които получават данни от HBase по подобен начин, като използвате MapperDriver, или да тествате MR задания, които четат от HBase, обработват данни и записват в HDFS.
Използване на мини-клъстер HBase
Сега ще разгледаме как да преминем към тестване на интеграция. HBase се доставя с HBaseTestingUtility, което прави писането на интеграционно тестване с мини-клъстер на HBase лесно. За да изтеглите правилните библиотеки, във вашия pom са необходими следните зависимости:
org.apache.hadoop hadoop-common 2.0.0-cdh4.2.0 test-jarтип> тест org.apache.hbase hbase 0.94.2-cdh4.2.0 test-jar test org.apache.hadoop hadoop-hdfs 2.0.0-cdh4.2.0 test-jar test org.apache.hadoop hadoop-hdfs 2.0.0-cdh4.2.0 test
Сега, нека да разгледаме как да преминем през интеграционен тест за MyDAO вложката, описана във въведението:
public class MyHBaseIntegrationTest {частна статична помощна програма HBaseTestingUtility;byte[] CF ="CF".getBytes();byte[] QUALIFIER ="CQ-1".getBytes();@Beforepublic void setup() хвърля изключение { помощна програма =нов HBaseTestingUtility(); utility.startMiniCluster();}@Test public void testInsert() хвърля изключение { HTableInterface table =utility.createTable(Bytes.toBytes("MyTest"), Bytes.toBytes("CF")); HBaseTestObj obj =нов HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1("ДАННИ-1"); obj.setData2("ДАННИ-2"); MyHBaseDAO.insertRecord(таблица, obj); Get get1 =new Get(Bytes.toBytes(obj.getRowKey())); get1.addColumn(CF, CQ1); Резултат резултат1 =table.get(get1); assertEquals(Bytes.toString(result1.getRow()), obj.getRowKey()); assertEquals(Bytes.toString(result1.value()), obj.getData1()); Get get2 =new Get(Bytes.toBytes(obj.getRowKey())); get2.addColumn(CF, CQ2); Резултат резултат2 =table.get(get2); assertEquals(Bytes.toString(result2.getRow()), obj.getRowKey()); assertEquals(Bytes.toString(result2.value()), obj.getData2()); }}
Тук създадохте мини-клъстер HBase и го стартирахте. След това създадохте таблица, наречена „MyTest“ с едно семейство колони, „CF“. Вмъкнахте запис с помощта на DAO, който трябваше да тествате, направихте Get от същата таблица и проверихте дали DAO е вмъкнал записи правилно.
Същото може да се направи и за много по-сложни случаи на използване заедно с MR задачи като тези, показани по-горе. Можете също да получите достъп до мини-клъстерите HDFS и ZooKeeper, създадени при създаването на HBase, да стартирате MR задание, да го изведете в HBase и да проверите вмъкнатите записи.
Само една бърза бележка за внимание:стартирането на мини-клъстер отнема 20 до 30 секунди и не може да се извърши на Windows без Cygwin. Въпреки това, тъй като те трябва да се изпълняват само периодично, по-дългото време за изпълнение трябва да е приемливо.
Можете да намерите примерен код за горните примери на https://github.com/sitaula/HBaseTest. Приятно тестване!