public class WordCountMapperTest {
private Mapper mapper;
private MapDriver driver;
@Before
public void init(){
mapper = new WordCountMapper();
driver = new MapDriver(mapper);
}
@Test
public void test() throws IOException{
String line = "Taobao is a great website";
driver.withInput(null,new Text(line))
.withOutput(new Text("Taobao"),new IntWritable(1))
.withOutput(new Text("is"), new IntWritable(1))
.withOutput(new Text("a"), new IntWritable(1))
.withOutput(new Text("great"), new IntWritable(1))
.withOutput(new Text("website"), new IntWritable(1))
.runTest();
}
}
@Test
public void test() throws RuntimeException, IOException{
String line = "Taobao is a great website, is it not?";
List<Pair> out = null;
out = driver.withInput("",new Text(line)).run();
List<Pair> expected = new ArrayList<Pair>();
expected.add(new Pair(new Text("Taobao"),new IntWritable(1)));
expected.add(new Pair(new Text("a"),new IntWritable(1)));
expected.add(new Pair(new Text("great"),new IntWritable(1)));
expected.add(new Pair(new Text("is"),new IntWritable(2)));
expected.add(new Pair(new Text("it"),new IntWritable(1)));
expected.add(new Pair(new Text("not"),new IntWritable(1)));
expected.add(new Pair(new Text("website"),new IntWritable(1)));
assertListEquals(expected, out);
}
再次运行,测试不通过,但有了明确的断言信息,
java.lang.AssertionError: Expected element (not, 1) at index 5 != actual element (not?, 1)
断言显示实际输出的结果为”not?”不是我们期待的”not”,为什么?检查Map函数,发现程序以空格为分隔符未考虑到标点符号的情况,哈哈,发现一个bug,赶紧修改吧。这个问题也反映了单元测试的重要性,想想看,如果是一个更加复杂的运算,不做单元测试直接放到分布式集群中去运行,当结果不符时就没这么容易定位出问题了。 小结
用MRUnit做单元测试可以归纳为以下几点:用MapDriver单独测试Map,用ReduceDriver单独测试Reduce,用MapReduceDriver测试MapReduce作业;不建议调用runTest方法,建议调用run方法获取输出结果,再跟期待结果相比较;对结果的断言可以借助org.apache.hadoop.mrunit.testutil.ExtendedAssert.assertListEquals。
如果你能坚持看到这里,我非常高兴,但我打赌,你肯定对前面大片的代码匆匆一瞥而过,这也正常,不是每个人都对测试实战的代码感兴趣(或在具体需要时才感兴趣),为了感谢你的关注,我再分享一个小秘密:本篇讲的不仅仅是如何对MapReduce做单元测试,通过本篇测试代码的阅读,你可以更加深刻的理解MapReduce的原理(通过测试代码的输入和预期结果,你可以更加清楚地知道map、reduce究竟输入、输出了什么,对结果的排序在何处进行等细节)。
单元测试很必要,可以较早较容易地发现定位问题,但只有单元测试是不够的,我们需要对MapReduce进行集成测试,在运行集成测试之前,需要掌握如何将MapReduce 作业在hadoop集群中运行起来,本系列后面的文章将介绍这部分内容。