如何单元测试Java Hbase API
How to unit test Java Hbase API
我正在使用 Java HBase API 从 Hbase 获取值。这是我的代码。
public class GetViewFromHbaseBolt extends BaseBasicBolt {
private HTable table;
private String zkQuorum;
private String zkClientPort;
private String tableName;
public GetViewFromHbaseBolt(String table, String zkQuorum,
String zkClientPort) {
this.tableName = table;
this.zkQuorum = zkQuorum;
this.zkClientPort = zkClientPort;
}
@Override
public void prepare(Map config, TopologyContext context) {
try {
table = getHTable();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
try {
if (tuple.size() > 0) {
Long dtmid = tuple.getLong(0);
byte[] rowKey = HBaseRowKeyDistributor.getDistributedKey(dtmid);
Get get = new Get(rowKey);
get.addFamily("a".getBytes());
Result result = table.get(get);
System.out.println(result);
byte[] bidUser = result.getValue("a".getBytes(),
"co_created_5076".getBytes());
collector.emit(new Values(dtmid, bidUser));
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("dtmi", "bidUser"));
}
// setting up the conections for Hbase
protected HTable getHTable() throws IOException {
HTable table = null;
Configuration conf;
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.property.clientPort", zkClientPort);
conf.set("hbase.zookeeper.quorum", zkQuorum);
table = new HTable(conf, tableName);
return table;
}
这很好用。现在我正在使用 Mockito API 编写单元测试。在我的测试中 class 我得到一个 java.langNullPointerException 当这个 when(table.get(any(Get.class))).thenReturn(result);被调用。
public class GetViewFromHbaseBoltTest {
@Mock
private TopologyContext topologyContext;
@Mock
private HTable table;
//HTable table = mock(HTable.class);
@Test
public void testExecute() throws IOException {
long dtmId = 350000000770902930L;
final byte[] COL_FAMILY = "a".getBytes();
final byte[] COL_QUALIFIER = "co_created_5076".getBytes();
// A mock tuple with a single dtmid
Tuple tuple = mock(Tuple.class);
when(tuple.size()).thenReturn(1);
when(tuple.getLong(0)).thenReturn(dtmId);
List<KeyValue> kvs = new ArrayList<KeyValue>();
kvs.add(new KeyValue(COL_FAMILY, COL_QUALIFIER, Bytes
.toBytes("ExpedtedBytes")));
Result result = new Result(kvs);
when(table.get(any(Get.class))).thenReturn(result);
BasicOutputCollector collector = mock(BasicOutputCollector.class);
GetViewFromHbaseBolt bolt = mock(GetViewFromHbaseBolt.class);
// Execute the bolt.
bolt.execute(tuple, collector);
ArgumentCaptor<Values> valuesArg = ArgumentCaptor
.forClass(Values.class);
verify(collector).emit(valuesArg.capture());
ArrayList<Object> d = valuesArg.getValue();
// verify
}
编辑
'Unit Test'是验证,验证一个特定的'unit of code'。如果 'unit of code' 依赖于外部调用,那么我们将这些调用模拟为 return 某些值。
如果您不从测试用例中调用 'actual unit of code',那么对代码进行单元测试有什么意义。明白了吗?
您应该只模拟来自实际方法的外部调用,而不是实际方法本身。
所以我会这样嘲笑:
@Mock
private HBaseRowKeyDistributor hDist;
@Mock
private HTable table;
@Test
public void sampleTest(){
//Mock data and external calls
final byte [] COL_FAMILY = "a".getBytes();
final byte [] COL_QUALIFIER = "co_created_5076".getBytes();
List<KeyValue> kvs =new ArrayList<KeyValue>();
kvs.add(new KeyValue(COL_FAMILY, COL_QUALIFIER,
Bytes.toBytes("ExpedtedBytes")));
Result result = new Result(kvs);
byte[] rowKey = "Hello".getBytes();
when(hdist.getDistributedKey(anyString()).thenReturn(rowKey);
when(table.get(any(Get.class))).thenReturn(result);
//Call the actual method
calloriginalUnitTestingMethod();
//Now Verify the result using Mockito verify like
verify(...)
//You could also intercept the attributes
}
也许您注意到您的代码测试不当table。可测试性差的原因是你的 class 做了两件事(创建一个 table 并执行一个元组)。我会建议您将 class 拆分为两个 classes 并将创建 table 的 class 注入执行元组的 class 中。
这 class 创建一个 Table:
public class HTableFactory {
private String tablename;
public HTableFactory(String tablename) {
this.tablename = tablename;
}
public HTable getTable() {}
}
然后你的 GetViewFromHbaseBolt
class 看起来像下面这样:
public class GetViewFromHbaseBolt extends BaseBasicBolt {
private HTableFactory factory;
private HTable table;
public GetViewFromHbaseBolt(HTableFactory factory) {}
@Override
public void prepare(Map config, TopologyContext context) {
table = factory.getTable();
}
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {}
}
现在您的 GetViewFromHbaseBolt
具有以下依赖项:
HTableFactory
Tuple
BasicOutputCollector
OutputFieldsDeclarer
在你的测试中class你可以模拟这个依赖并将它们注入GetViewFromHbaseBold
。
你检查过你的模拟初始化正确吗?我不是 Mockito 的专家,但在我看来,您需要将测试 运行ner 设置为 Mockito 运行ner 或显式初始化带注释的模拟 (@Mock)。例如,参见 Using @Mock and @InjectMocks
我的猜测是,当您 运行 生成 NullPointer 的行时,您的 "table" 变量为空。
我正在使用 Java HBase API 从 Hbase 获取值。这是我的代码。
public class GetViewFromHbaseBolt extends BaseBasicBolt {
private HTable table;
private String zkQuorum;
private String zkClientPort;
private String tableName;
public GetViewFromHbaseBolt(String table, String zkQuorum,
String zkClientPort) {
this.tableName = table;
this.zkQuorum = zkQuorum;
this.zkClientPort = zkClientPort;
}
@Override
public void prepare(Map config, TopologyContext context) {
try {
table = getHTable();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
try {
if (tuple.size() > 0) {
Long dtmid = tuple.getLong(0);
byte[] rowKey = HBaseRowKeyDistributor.getDistributedKey(dtmid);
Get get = new Get(rowKey);
get.addFamily("a".getBytes());
Result result = table.get(get);
System.out.println(result);
byte[] bidUser = result.getValue("a".getBytes(),
"co_created_5076".getBytes());
collector.emit(new Values(dtmid, bidUser));
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("dtmi", "bidUser"));
}
// setting up the conections for Hbase
protected HTable getHTable() throws IOException {
HTable table = null;
Configuration conf;
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.property.clientPort", zkClientPort);
conf.set("hbase.zookeeper.quorum", zkQuorum);
table = new HTable(conf, tableName);
return table;
}
这很好用。现在我正在使用 Mockito API 编写单元测试。在我的测试中 class 我得到一个 java.langNullPointerException 当这个 when(table.get(any(Get.class))).thenReturn(result);被调用。
public class GetViewFromHbaseBoltTest {
@Mock
private TopologyContext topologyContext;
@Mock
private HTable table;
//HTable table = mock(HTable.class);
@Test
public void testExecute() throws IOException {
long dtmId = 350000000770902930L;
final byte[] COL_FAMILY = "a".getBytes();
final byte[] COL_QUALIFIER = "co_created_5076".getBytes();
// A mock tuple with a single dtmid
Tuple tuple = mock(Tuple.class);
when(tuple.size()).thenReturn(1);
when(tuple.getLong(0)).thenReturn(dtmId);
List<KeyValue> kvs = new ArrayList<KeyValue>();
kvs.add(new KeyValue(COL_FAMILY, COL_QUALIFIER, Bytes
.toBytes("ExpedtedBytes")));
Result result = new Result(kvs);
when(table.get(any(Get.class))).thenReturn(result);
BasicOutputCollector collector = mock(BasicOutputCollector.class);
GetViewFromHbaseBolt bolt = mock(GetViewFromHbaseBolt.class);
// Execute the bolt.
bolt.execute(tuple, collector);
ArgumentCaptor<Values> valuesArg = ArgumentCaptor
.forClass(Values.class);
verify(collector).emit(valuesArg.capture());
ArrayList<Object> d = valuesArg.getValue();
// verify
}
编辑
'Unit Test'是验证,验证一个特定的'unit of code'。如果 'unit of code' 依赖于外部调用,那么我们将这些调用模拟为 return 某些值。
如果您不从测试用例中调用 'actual unit of code',那么对代码进行单元测试有什么意义。明白了吗?
您应该只模拟来自实际方法的外部调用,而不是实际方法本身。
所以我会这样嘲笑:
@Mock
private HBaseRowKeyDistributor hDist;
@Mock
private HTable table;
@Test
public void sampleTest(){
//Mock data and external calls
final byte [] COL_FAMILY = "a".getBytes();
final byte [] COL_QUALIFIER = "co_created_5076".getBytes();
List<KeyValue> kvs =new ArrayList<KeyValue>();
kvs.add(new KeyValue(COL_FAMILY, COL_QUALIFIER,
Bytes.toBytes("ExpedtedBytes")));
Result result = new Result(kvs);
byte[] rowKey = "Hello".getBytes();
when(hdist.getDistributedKey(anyString()).thenReturn(rowKey);
when(table.get(any(Get.class))).thenReturn(result);
//Call the actual method
calloriginalUnitTestingMethod();
//Now Verify the result using Mockito verify like
verify(...)
//You could also intercept the attributes
}
也许您注意到您的代码测试不当table。可测试性差的原因是你的 class 做了两件事(创建一个 table 并执行一个元组)。我会建议您将 class 拆分为两个 classes 并将创建 table 的 class 注入执行元组的 class 中。
这 class 创建一个 Table:
public class HTableFactory {
private String tablename;
public HTableFactory(String tablename) {
this.tablename = tablename;
}
public HTable getTable() {}
}
然后你的 GetViewFromHbaseBolt
class 看起来像下面这样:
public class GetViewFromHbaseBolt extends BaseBasicBolt {
private HTableFactory factory;
private HTable table;
public GetViewFromHbaseBolt(HTableFactory factory) {}
@Override
public void prepare(Map config, TopologyContext context) {
table = factory.getTable();
}
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {}
}
现在您的 GetViewFromHbaseBolt
具有以下依赖项:
HTableFactory
Tuple
BasicOutputCollector
OutputFieldsDeclarer
在你的测试中class你可以模拟这个依赖并将它们注入GetViewFromHbaseBold
。
你检查过你的模拟初始化正确吗?我不是 Mockito 的专家,但在我看来,您需要将测试 运行ner 设置为 Mockito 运行ner 或显式初始化带注释的模拟 (@Mock)。例如,参见 Using @Mock and @InjectMocks
我的猜测是,当您 运行 生成 NullPointer 的行时,您的 "table" 变量为空。