`
liuxinglanyue
  • 浏览: 557234 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Hadoop学习笔记之三:用MRUnit做单元测试

阅读更多

 

转载务必注明出处Taobao QA Team,原文地址:http://qa.taobao.com/?p=10550

引言
年底盛宴品鉴之风,继续抒我Hadoop之情,本篇文章介绍如何对Hadoop的MapReduce进行单元测试。MapReduce的开发周期差不多是这样:编写mapper和reducer、编译、打包、提交作业和结果检索等,这个过程比较繁琐,一旦提交到分布式环境出了问题要定位调试,重复这样的过程实在无趣,因此先对MapReduce做单元测试,消除明显的代码bug尤为必要。

MRUnit简介
MRUnit是一款由Couldera公司开发的专门针对Hadoop中编写MapReduce单元测试的框架。可以用MapDriver单独测试Map,用ReduceDriver单独测试Reduce,用MapReduceDriver测试MapReduce作业。

实战
我们将利用MRUnit对本系列上篇文章MapReduce基本编程中的字数统计功能进行单元测试。

  • 加入MRUnit依赖
  •  

     

    <dependency>
    	<groupId>com.cloudera.hadoop</groupId>
    	<artifactId>hadoop-mrunit</artifactId>
    	<version>0.20.2-320</version>
    	<scope>test</scope>
    </dependency>
     

  • 单独测试Map
  •  

    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();
    	}
        }
     

    上面的例子通过MapDriver的withInput和withOutput组织map函数的输入键值和期待的输出键值,通过runTest方法运行作业,测试Map函数。 测试运行通过。

  • 单独测试Reduce
  • public class WordCountReducerTest {
      private Reducer reducer;
      private ReduceDriver driver;
    
      @Before
       public void init(){
         reducer = new WordCountReducer();
         driver = new ReduceDriver(reducer);
       }
      @Test
      public void test() throws IOException{
        String key = "taobao";
        List values = new ArrayList();
        values.add(new IntWritable(2));
        values.add(new IntWritable(3));
    
        driver.withInput(new Text("taobao"), values)
               .withOutput(new Text("taobao"), new IntWritable(5))
               .runTest();
       }
    }
     上面的例子的测试Map函数的写法类似,测试reduce函数

    因为reduce函数实现相加功能,因此我们假设输入为<taobao,[2,3]>,
    则期待结果应该为<taobao,5>.测试运行通过。

  • 测试MapReduce
  • public class WordCountTest {
      private Mapper mapper;
      private Reducer reducer;
      private MapReduceDriver driver;
    
      @Before
       public void init(){
         mapper = new WordCountMapper();
         reducer = new WordCountReducer();
         driver = new MapReduceDriver(mapper,reducer);
       }
    
        @Test
         public void test() throws RuntimeException, IOException{
           String line = "Taobao is a great website, is it not?";
           driver.withInput("",new Text(line))
    	.withOutput(new Text("Taobao"),new IntWritable(1))
    	.withOutput(new Text("a"),new IntWritable(1))
    	.withOutput(new Text("great"),new IntWritable(1))
    	.withOutput(new Text("is"),new IntWritable(2))
    	.withOutput(new Text("it"),new IntWritable(1))
    	.withOutput(new Text("not"),new IntWritable(1))
    	.withOutput(new Text("website"),new IntWritable(1))
    	.runTest();
          }
    }
     

    这次我们测试MapReduce的作业,通过MapReduceDriver的withInput构造map函数的输入键值,通过withOutput构造reduce函数的输出键值。来测试这个字数统计功能,这次运行测试时抛出了异常,测试没有通过但没有详细junit异常信息,在控制台显示

    2010-11-5 11:14:08 org.apache.hadoop.mrunit.TestDriver lookupExpectedValue严重:Received unexpected output (not?, 1)
    2010-11-5 11:14:08 org.apache.hadoop.mrunit.TestDriver lookupExpectedValue严重: Received unexpected output (website,, 1)
    2010-11-5 11:14:08 org.apache.hadoop.mrunit.TestDriver validate严重:Missing expected output (not, 1) at position 5
    2010-11-5 11:14:08 org.apache.hadoop.mrunit.TestDriver validate严重:Missing expected output (website, 1) at position 6

    看样子是那里出了问题,不过看控制台日志不是很直观,因此我们修改测试代码,不调用runTest方法,而是调用run方法获取输出结果,再跟期待结果相比较,mrunit提供了org.apache.hadoop.mrunit.testutil.ExtendedAssert.assertListEquals辅助类来断言输出结果。

  • 重构后的测试代码
  •  

    @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集群中运行起来,本系列后面的文章将介绍这部分内容。

    分享到:
    评论
    3 楼 liuxinglanyue 2011-03-25  
    guafei 写道
    请问下,我使用了org.apache.hadoop.mrunit.testutil.ExtendedAssert.assertListEquals这个方法,但是却没有出现java.lang.AssertionError: Expected element (not, 1) at index 5 != actual element (not?, 1)这句话的提示,请问是为什么?
    还有你应该是淘宝的吧,你的花名是什么,我加下你。谢谢!

    可能是hadoop版本和MRUnit的兼容问题,这篇文章用的是 hadoop-0.20.2
    还有原文在这里:http://qa.taobao.com/?p=10550
    2 楼 liuxinglanyue 2011-03-25  
    guafei 写道
    请问下,我使用了org.apache.hadoop.mrunit.testutil.ExtendedAssert.assertListEquals这个方法,但是却没有出现java.lang.AssertionError: Expected element (not, 1) at index 5 != actual element (not?, 1)这句话的提示,请问是为什么?
    还有你应该是淘宝的吧,你的花名是什么,我加下你。谢谢!

    我还是个学生。
    1 楼 guafei 2011-03-25  
    请问下,我使用了org.apache.hadoop.mrunit.testutil.ExtendedAssert.assertListEquals这个方法,但是却没有出现java.lang.AssertionError: Expected element (not, 1) at index 5 != actual element (not?, 1)这句话的提示,请问是为什么?
    还有你应该是淘宝的吧,你的花名是什么,我加下你。谢谢!

    相关推荐

      hadoop学习笔记.rar

      三、Hadoop学习笔记之三:用MRUnit做单元测试 MRUnit是针对MapReduce任务的单元测试框架,它允许开发者对MapReduce作业进行单元测试,确保每个Mapper和Reducer的功能正确性。通过MRUnit,可以在不实际运行Hadoop集群...

      hadoop-mrunit-0.20.2-cdh3u4.jar

      用于hadoop单元测试的jar包 hadoop-mrunit-0.20.2-cdh3u4.jar

      Hadoop学习笔记

      Hadoop学习笔记,自己总结的一些Hadoop学习笔记,比较简单。

      最新Hadoop学习笔记

      **Hadoop学习笔记详解** Hadoop是一个开源的分布式计算框架,由Apache基金会开发,主要用于处理和存储海量数据。它的核心组件包括HDFS(Hadoop Distributed File System)和MapReduce,两者构成了大数据处理的基础...

      Mrunit-1.1.0-hadoop2

      - 编写测试类:Mrunit提供了模拟MapReduce作业的类,如`org.apache.hadoop.mapreduce.lib.map.MockMapper`和`org.apache.hadoop.mapreduce.lib.reduce.MockReducer`。开发者可以通过继承这些类,覆盖必要的方法来...

      apache-mrunit-1.1.0-hadoop2-bin.tar

      4. **易于集成**:MRUnit可以轻松地与JUnit或其他测试框架集成,使得开发者能够在现有的测试框架中添加MapReduce单元测试,进一步提升测试覆盖率和代码质量。 5. **异常处理**:MRUnit还帮助开发者识别和测试Mapper...

      Hadoop 学习笔记.md

      Hadoop 学习笔记.md

      Hadoop MRUnit测试

      Hadoop MRUnit是一个用于测试MapReduce程序的强大工具,它允许开发者在没有实际Hadoop集群的情况下,对MapReduce作业进行单元测试。这个框架模拟了Hadoop MapReduce的执行环境,使开发者可以针对单个Mapper、Reducer...

      hadoop学习笔记(三)

      在本篇"Hadoop学习笔记(三)"中,我们将探讨如何使用Hadoop的MapReduce框架来解决一个常见的问题——从大量数据中找出最大值。这个问题与SQL中的`SELECT MAX(NUMBER) FROM TABLE`查询相似,但在这里我们通过编程...

      HADOOP学习笔记

      【HADOOP学习笔记】 Hadoop是Apache基金会开发的一个开源分布式计算框架,是云计算领域的重要组成部分,尤其在大数据处理方面有着广泛的应用。本学习笔记将深入探讨Hadoop的核心组件、架构以及如何搭建云计算平台。...

      3.Hadoop学习笔记.pdf

      Hadoop是一个开源框架,用于存储和处理大型数据集。由Apache软件基金会开发,Hadoop已经成为大数据处理事实上的标准。...通过使用Hadoop,企业和组织可以在不牺牲数据完整性和可靠性的前提下,处理和分析海量的数据集。

      mrunit-1.1.0.jar

      5. **集成JUnit**:MRUnit与流行的Java测试框架JUnit紧密结合,使得MapReduce测试能够无缝融入到开发者的测试流程中。 6. **性能评估**:虽然MRUnit主要是用于功能测试,但通过本地运行,开发者也可以初步评估...

      云计算hadoop学习笔记

      云计算,hadoop,学习笔记, dd

      Hadoop学习笔记.pdf

      首先,Hadoop的分布式文件系统(HDFS)是其核心组件之一,它具有高吞吐量的数据访问能力,非常适合大规模数据集的存储和处理。HDFS的设计是基于这样的理念:硬件故障是常态,因此它通过数据复制机制来实现高可靠性。...

      hadoop-auth-2.6.5-API文档-中英对照版.zip

      赠送jar包:hadoop-auth-2.6.5.jar 赠送原API文档:hadoop-auth-2.6.5-javadoc.jar 赠送源代码:hadoop-auth-2.6.5-sources.jar 包含翻译后的API文档:hadoop-auth-2.6.5-javadoc-API文档-中文(简体)-英语-对照版...

    Global site tag (gtag.js) - Google Analytics