`
liuxinglanyue
  • 浏览: 572736 次
  • 性别: 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集群...

      MapReduceV2笔记

      为了保证MapReduce程序的正确性和稳定性,MapReduce提供了用MRUnit进行程序测试的方法。计数器是MapReduce中的一个功能,它可以帮助用户追踪和统计程序运行中的各种事件。 性能优化是MapReduce应用中的关键话题,它...

      基于MATLAB GUI与CNN的模糊车牌识别系统:从图像预处理到字符识别全流程解析

      内容概要:本文详细介绍了基于MATLAB GUI界面和卷积神经网络(CNN)的模糊车牌识别系统。该系统旨在解决现实中车牌因模糊不清导致识别困难的问题。文中阐述了整个流程的关键步骤,包括图像的模糊还原、灰度化、阈值化、边缘检测、孔洞填充、形态学操作、滤波操作、车牌定位、字符分割以及最终的字符识别。通过使用维纳滤波或最小二乘法约束滤波进行模糊还原,再利用CNN的强大特征提取能力完成字符分类。此外,还特别强调了MATLAB GUI界面的设计,使得用户能直观便捷地操作整个系统。 适合人群:对图像处理和深度学习感兴趣的科研人员、高校学生及从事相关领域的工程师。 使用场景及目标:适用于交通管理、智能停车场等领域,用于提升车牌识别的准确性和效率,特别是在面对模糊车牌时的表现。 其他说明:文中提供了部分关键代码片段作为参考,并对实验结果进行了详细的分析,展示了系统在不同环境下的表现情况及其潜在的应用前景。

      嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip

      嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip

      嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip

      嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip

      开关磁阻电机技术参数与建模技术深度解析:4kW电机性能详述

      内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。

      少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip

      少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip

      少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip

      少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip

      四象限直流电机速度驱动控制系统PID控制仿真模型设计与实现

      内容概要:本文详细介绍了基于PID控制器的四象限直流电机速度驱动控制系统仿真模型及其永磁直流电机(PMDC)转速控制模型。首先阐述了PID控制器的工作原理,即通过对系统误差的比例、积分和微分运算来调整电机的驱动信号,从而实现转速的精确控制。接着讨论了如何利用PID控制器使有刷PMDC电机在四个象限中精确跟踪参考速度,并展示了仿真模型在应对快速负载扰动时的有效性和稳定性。最后,提供了Simulink仿真模型和详细的Word模型说明文档,帮助读者理解和调整PID控制器参数,以达到最佳控制效果。 适合人群:从事电力电子与电机控制领域的研究人员和技术人员,尤其是对四象限直流电机速度驱动控制系统感兴趣的读者。 使用场景及目标:适用于需要深入了解和掌握四象限直流电机速度驱动控制系统设计与实现的研究人员和技术人员。目标是在实际项目中能够运用PID控制器实现电机转速的精确控制,并提高系统的稳定性和抗干扰能力。 其他说明:文中引用了多篇相关领域的权威文献,确保了理论依据的可靠性和实用性。此外,提供的Simulink模型和Word文档有助于读者更好地理解和实践所介绍的内容。

      嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip

      嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip

      少儿编程scratch项目源代码文件案例素材-驾驶通关.zip

      少儿编程scratch项目源代码文件案例素材-驾驶通关.zip

      小区开放对周边道路通行能力影响的研究.pdf

      小区开放对周边道路通行能力影响的研究.pdf

      冷链物流路径优化:基于NSGA-2遗传算法与软硬时间窗策略的研究

      内容概要:本文探讨了冷链物流车辆路径优化问题,特别是如何通过NSGA-2遗传算法和软硬时间窗策略来实现高效、环保和高客户满意度的路径规划。文中介绍了冷链物流的特点及其重要性,提出了软时间窗概念,允许一定的配送时间弹性,同时考虑碳排放成本,以达到绿色物流的目的。此外,还讨论了如何将客户满意度作为路径优化的重要评价标准之一。最后,通过一段简化的Python代码展示了遗传算法的应用。 适合人群:从事物流管理、冷链物流运营的专业人士,以及对遗传算法和路径优化感兴趣的科研人员和技术开发者。 使用场景及目标:适用于冷链物流企业,旨在优化配送路线,降低运营成本,减少碳排放,提升客户满意度。目标是帮助企业实现绿色、高效的物流配送系统。 其他说明:文中提供的代码仅为示意,实际应用需根据具体情况调整参数设置和模型构建。

      少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip

      少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip

      基于STM32F030的无刷电机高压FOC控制方案:滑膜无感FOC技术及保护机制

      内容概要:本文详细介绍了基于STM32F030的无刷电机控制方案,重点在于高压FOC(磁场定向控制)技术和滑膜无感FOC的应用。该方案实现了过载、过欠压、堵转等多种保护机制,并提供了完整的源码、原理图和PCB设计。文中展示了关键代码片段,如滑膜观测器和电流环处理,以及保护机制的具体实现方法。此外,还提到了方案的移植要点和实际测试效果,确保系统的稳定性和高效性。 适合人群:嵌入式系统开发者、电机控制系统工程师、硬件工程师。 使用场景及目标:适用于需要高性能无刷电机控制的应用场景,如工业自动化设备、无人机、电动工具等。目标是提供一种成熟的、经过验证的无刷电机控制方案,帮助开发者快速实现并优化电机控制性能。 其他说明:提供的资料包括详细的原理图、PCB设计文件、源码及测试视频,方便开发者进行学习和应用。

      基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf

      基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf

      嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip

      嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip

      少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip

      少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip

      Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统.zip

      Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统

      C# WPF - LiveCharts Project

      C# WPF - LiveCharts Project

    Global site tag (gtag.js) - Google Analytics