Während die Akzeptanz von Apache HBase zum Erstellen von Endbenutzeranwendungen in die Höhe geschossen ist, wurden viele dieser Anwendungen (und viele Apps im Allgemeinen) nicht gut getestet. In diesem Beitrag erfahren Sie, wie diese Tests einfach durchgeführt werden können.
Wir beginnen mit Komponententests über JUnit, fahren dann mit Mockito und Apache MRUnit fort und verwenden dann einen HBase-Mini-Cluster für Integrationstests. (Die HBase-Codebasis selbst wird über einen Mini-Cluster getestet, warum also nicht auch für Upstream-Anwendungen darauf zurückgreifen?)
Nehmen wir als Diskussionsgrundlage an, Sie haben ein HBase-Datenzugriffsobjekt (DAO), das die folgende Einfügung in HBase vornimmt. Die Logik könnte natürlich komplizierter sein, aber zum Beispiel erfüllt dies die Aufgabe.
public class MyHBaseDAO { public static void insertRecord(HTableInterface table, HBaseTestObj obj) löst Exception aus { Put put =createPut(obj); Tabelle.put(put); } privates statisches Put createPut(HBaseTestObj obj) {Put 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())); Rückgabe setzen; }}
HBaseTestObj ist ein einfaches Datenobjekt mit Gettern und Settern für rowkey, data1 und data2.
Der insertRecord führt eine Einfügung in die HBase-Tabelle für die Spaltenfamilie von CF mit CQ-1 und CQ-2 als Qualifizierern durch. Die createPut-Methode füllt einfach einen Put und gibt ihn an die aufrufende Methode zurück.
Mit JUnit
JUnit, das den meisten Java-Entwicklern inzwischen gut bekannt ist, lässt sich problemlos auf viele HBase-Anwendungen anwenden. Fügen Sie zuerst die Abhängigkeit zu Ihrem Pom hinzu:
junit junit 4.11 test
Nun, innerhalb der Testklasse:
public class TestMyHbaseDAOData { @Test public void testCreatePut() löst Exception aus { HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1 ("DATA-1"); obj.setData2 ("DATA-2"); Put 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())); } }
Was Sie hier getan haben, war sicherzustellen, dass Ihre createPut-Methode ein Put-Objekt mit erwarteten Werten erstellt, füllt und zurückgibt.
Mockito verwenden
Wie gehen Sie also vor, um die obige insertRecord-Methode zu testen? Ein sehr effektiver Ansatz ist Mockito.
Fügen Sie zuerst Mockito als Abhängigkeit zu Ihrem Pom hinzu:
org.mockito mockito-all 1.9.5 test
Dann in der Testklasse:
@RunWith(MockitoJUnitRunner.class)öffentliche Klasse TestMyHBaseDAO{ @Mock private HTableInterface-Tabelle; @Mock privater HTablePool hTablePool; @Captor privat ArgumentCaptor putCaptor; @Test public void testInsertRecord() löst Ausnahme aus { //Pseudotabelle zurückgeben, wenn getTable aufgerufen wird when(hTablePool.getTable("tablename")).thenReturn(table); //Testobjekt erstellen und DAO aufrufen, das getestet werden muss HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1 ("DATA-1"); obj.setData2 ("DATA-2"); MyHBaseDAO.insertRecord(table, obj); verifizieren (Tabelle). Put (putCaptor. Capture ()); Put 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"); }}
Hier haben Sie HBaseTestObj mit „ROWKEY-1“, „DATA-1“, „DATA-2“ als Werte gefüllt. Anschließend haben Sie die simulierte Tabelle und das DAO verwendet, um den Datensatz einzufügen. Sie haben den Put erfasst, den das DAO eingefügt hätte, und überprüft, ob rowkey, data1 und data2 Ihren Erwartungen entsprechen.
Der Schlüssel hier ist die Verwaltung des Htable-Pools und der Htable-Instanzerstellung außerhalb des DAO. Auf diese Weise können Sie sie sauber verspotten und Puts wie oben gezeigt testen. In ähnlicher Weise können Sie jetzt alle anderen Operationen wie Abrufen, Scannen, Löschen usw. erweitern.
MRUnit verwenden
Wenden wir uns nach dem regulären Unit-Test für den Datenzugriff nun MapReduce-Jobs zu, die gegen HBase-Tabellen verstoßen.
Das Testen von MR-Jobs, die gegen HBase verstoßen, ist so einfach wie das Testen regulärer MapReduce-Jobs. MRUnit macht es wirklich einfach, MapReduce-Jobs einschließlich der HBase-Jobs zu testen.
Stellen Sie sich vor, Sie haben einen MR-Job, der in eine HBase-Tabelle „MyTest“ schreibt, die eine Spaltenfamilie „CF“ hat. Der Reducer eines solchen Jobs könnte so aussehen:
öffentliche Klasse MyReducer erweitert TableReducer{ public static final byte[] CF ="CF".getBytes(); öffentliches statisches Endbyte[] QUALIFIER ="CQ-1".getBytes(); public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { //Haufen von Verarbeitung zum Extrahieren einzufügender Daten, in unserem Fall sagen wir, wir hängen einfach //alle Datensätze an, die wir erhalten aus dem Mapper für diesen bestimmten //Schlüssel und füge einen Datensatz in HBase ein StringBuffer data =new StringBuffer(); Put put =new Put(Bytes.toBytes(key.toString())); for (Textwert:Werte) { data =data.append (val); } put.add (CF, QUALIFIER, Bytes.toBytes (data.toString())); //in HBase schreiben context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())), put); } }
Wie gehen Sie nun vor, um den obigen Reduzierer in MRUnit zu testen? Fügen Sie zuerst MRUnit als Abhängigkeit zu Ihrem Pom hinzu.
org.apache.mrunit mrunit 1.0.0 test
Verwenden Sie dann innerhalb der Testklasse den von MRUnit bereitgestellten ReduceDriver wie folgt:
öffentliche Klasse MyReducerTest { ReduceDriverReduceDriver; byte[] CF ="CF".getBytes(); byte[] QUALIFIER ="CQ-1".getBytes(); @Before public void setUp() { MyReducer Reducer =new MyReducer(); ReduceDriver =ReduceDriver.newReduceDriver (Reduzierer); } @Test public void testHBaseInsert() löst IOException aus { String strKey ="RowKey-1", strValue ="DATA", strValue1 ="DATA1", strValue2 ="DATA2"; List list =new ArrayList (); list.add (neuer Text (strValue)); list.add (neuer Text (strValue1)); list.add (neuer Text (strValue2)); //Da der Reducer in unserem Fall nur die Datensätze anhängt, die der Mapper //sendet, sollten wir Folgendes zurückbekommen: String ExpectedOutput =strValue + strValue1 + strValue2; //Eingabe einrichten, nachahmen, was der Mapper übergeben hätte //an den Reducer und Test ausführen ReduceDriver.withInput(new Text(strKey), list); //Reduzierer ausführen und Ausgabe abrufen List > result =ReduceDriver.run(); //Schlüssel aus Ergebnis extrahieren und prüfen asserEquals(Bytes.toString(result.get(0).getFirst().get()), strKey); //Wert für CF/QUALIFIER extrahieren und prüfen Put a =(Put)result.get(0).getSecond(); String c =Bytes.toString(a.get(CF, QUALIFIER).get(0).getValue()); assertEquals (erwartete Ausgabe, c); }}
Grundsätzlich haben Sie nach einer Reihe von Verarbeitungen in MyReducer Folgendes überprüft:
- Die Ausgabe entspricht Ihren Erwartungen.
- Der Put, der in HBase eingefügt wird, hat „RowKey-1“ als Zeilenschlüssel.
- "DATADATA1DATA2" ist der Wert für die CF-Spaltenfamilie und den CQ-Spaltenqualifizierer.
Sie können auch Mapper testen, die Daten von HBase auf ähnliche Weise mit MapperDriver abrufen, oder MR-Jobs testen, die von HBase lesen, Daten verarbeiten und in HDFS schreiben.
Verwendung eines HBase-Mini-Clusters
Jetzt schauen wir uns an, wie man Integrationstests durchführt. HBase wird mit HBaseTestingUtility geliefert, das das Schreiben von Integrationstests mit einem HBase-Mini-Cluster vereinfacht. Um die richtigen Bibliotheken einzubinden, sind die folgenden Abhängigkeiten in Ihrem Pom erforderlich:
org.apache.hadoop hadoop-common 2.0.0-cdh4.2.0 test-jar test 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
Sehen wir uns nun an, wie Sie einen Integrationstest für die in der Einführung beschriebene MyDAO-Einfügung durchführen:
public class MyHBaseIntegrationTest {private static HBaseTestingUtility Utility;byte[] CF ="CF".getBytes();byte[] QUALIFIER ="CQ-1".getBytes();@Beforepublic void setup() throws Exception { Utility =neues HBaseTestingUtility(); Utility.startMiniCluster();}@Test public void testInsert() löst Ausnahme aus { HTableInterface table =Utility.createTable(Bytes.toBytes("MyTest"), Bytes.toBytes("CF")); HBaseTestObj obj =new HBaseTestObj(); obj.setRowKey("ROWKEY-1"); obj.setData1 ("DATA-1"); obj.setData2 ("DATA-2"); MyHBaseDAO.insertRecord(table, obj); Get get1 =new Get (Bytes.toBytes (obj.getRowKey())); get1.addColumn (CF, CQ1); Ergebnis result1 =table.get(get1); assertEquals(Bytes.toString(result1.getRow()), obj.getRowKey()); assertEquals(Bytes.toString(result1.value()), obj.getData1()); Get2 =new Get(Bytes.toBytes(obj.getRowKey())); get2.addColumn (CF, CQ2); Ergebnis result2 =table.get(get2); assertEquals(Bytes.toString(result2.getRow()), obj.getRowKey()); assertEquals(Bytes.toString(result2.value()), obj.getData2()); }}
Hier haben Sie einen HBase-Mini-Cluster erstellt und gestartet. Anschließend haben Sie eine Tabelle mit dem Namen „MyTest“ mit einer Spaltenfamilie „CF“ erstellt. Sie haben mit dem zu testenden DAO einen Datensatz eingefügt, aus derselben Tabelle abgerufen und überprüft, ob das DAO die Datensätze korrekt eingefügt hat.
Das gleiche könnte für viel kompliziertere Anwendungsfälle zusammen mit den MR-Jobs wie den oben gezeigten gemacht werden. Sie können auch auf die beim Erstellen des HBase-Clusters erstellten HDFS- und ZooKeeper-Mini-Cluster zugreifen, einen MR-Job ausführen, diesen an HBase ausgeben und die eingefügten Datensätze überprüfen.
Nur eine kurze Warnung:Das Starten eines Mini-Clusters dauert 20 bis 30 Sekunden und kann unter Windows ohne Cygwin nicht durchgeführt werden. Da sie jedoch nur periodisch ausgeführt werden sollten, sollte die längere Laufzeit akzeptabel sein.
Beispielcode für die obigen Beispiele finden Sie unter https://github.com/sitaula/HBaseTest. Viel Spaß beim Testen!