`
Teok
  • 浏览: 150671 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

写可测试的代码

阅读更多
这两天在琢磨如何写测试代码。有点感触,在这里慢慢整理出来:
  • Mock。mock的英文意思是模仿、虚假,在软件测试里面,它代表一种测试手段和思路。跟同事请教了mock的基本用途和使用方法之后,我就觉得把mock描述为一种测试策略更准确点(我也没有系统的学习过测试相关理论,这里也是怎么想怎么说)。EasyMock这样的类库,就是这种策略的一个实现。说明这一点是因为第一次听到另外一个同事介绍Mock时把它解释为一个东西,我了解之后,我觉得不是东西,是模拟被测试类的依赖者而达到测试的目的的一种方法。
  • 对于抽象类,不用单独去测试。实际上也没法测试。直接去测试它的inheritors就可以了。
  • 每个程序员都要明白测试的技术,才能写出可测试的代码。我今天自己给自己前两天写的一个小应用写测试代码,主要是为了学习测试的流程,没写一会,就发现,我之前有些代码写的根本不具备可测试性。我问同事,碰到这种情况怎么办,他说,改实现代码,再接着写测试代码(我们目前没有进行TDD开发,测试代码都是后期补的)。所以我想,既然要去返工,其实也就证明自己写的代码是不合格的,转念一想,如果自己写的代码,某天不是自测,而是他人测试时,被改的“面目全非”,那岂不是很惭愧。因此一定要真正写过测试代码了,再去带着写可测试代码的那种想法去写代码,你这个环节的质量合格,整体质量和效率才会提高。经过长期的练习与实践,当这种想法已经成为编码习惯,那么才有资格说自己是个合格的程序员。
  • 事实上我不得不抱怨Android测试框架,真的很难用。当你使用Android测试api,如果使用错误,这个框架几乎不会给我报告有用的信息让你track问题。就在刚才,我花了几个小时在找一个看起来挺蠢的问题。(见http://code.google.com/p/android/issues/detail?id=8501,碰到这样的问题,真是泪奔)。所以,1.记得给那些你要用到的类加上一个public的无参构造器。2.记得不要开多个ide,然后再运行测试代码。
  • 如何控制和监控Activity的生命周期,以达到测试的目的?有一种做法,就是克隆Activity的
  • 生命周期控制api(题外话:生命周期api,onCreate,onResume等,如果要从设计模式来看,不就是Template Methods吗)。然后定义一个基类Activity实现这些克隆,让克隆api和Activity自由的生命周期api联系起来(让这个基类成为一个facade)。当要测试某个Activity时,只要给基类里的克隆api接口变量注入一个实现实例即可。可能没说清楚,就让代码来解释:
    package com.nsworks.testdemo.util;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    /**
     * The super base activity for all activities, each activity should inherit it.
     */
    public class BaseActivity extends Activity {
    	public interface ActivityLifeCycleController {
    		public void onCreate(BaseActivity instance, Bundle myCycle);
    		public void onStart(BaseActivity instance);
    		public void onResume(BaseActivity instance);
    		public void onPostResume(BaseActivity instance);
    		public void onPause(BaseActivity instance);
    		public void onStop(BaseActivity instance);
    		public void onDestroy(BaseActivity instance);
    	}
    	// Note: this field must be declared static in order to be injected
    	// in test framework implementations.
    	private static ActivityLifeCycleController mCycleController;
    	// Note: Android test framework need each class to have a public constructor
    	// without any parameters
    	// I think this is weird, but if a class has not a such constructor will
    	// cause a failure.
    	public BaseActivity() {
    		// Do something
    	}
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		if (mCycleController != null) {
    			mCycleController.onCreate(this, savedInstanceState);
    		}
    	}
    	@Override
    	protected void onStart() {
    		super.onStart();
    		if (mCycleController != null) {
    			mCycleController.onStart(this);
    		}
    	}
    	@Override
    	protected void onResume() {
    		super.onResume();
    		if (mCycleController != null) {
    			mCycleController.onResume(this);
    		}
    	}
    	@Override
    	protected void onPostResume() {
    		super.onPostResume();
    		if(mCycleController != null) {
    			mCycleController.onPostResume(this);
    		}
    	}
    	@Override
    	protected void onPause() {
    		super.onPause();
    		if (mCycleController != null) {
    			mCycleController.onPause(this);
    		}
    	}
    	@Override
    	protected void onStop() {
    		super.onStop();
    		if (mCycleController != null) {
    			mCycleController.onStop(this);
    		}
    	}
    	@Override
    	protected void onDestroy() {
    		super.onDestroy();
    		if (mCycleController != null) {
    			mCycleController.onDestroy(this);
    		}
    	}
    }
    
    

    接着,所要做的是在测试环境初始化的过程中加入注入操作:
    MemberAccessor.searchSuperField(DayActivity.class, "mDbFacade", new MockCTDbFacade());

    看看MemberAccessor工具类的实现:
    	public static Class<?> searchSuperField(Class<?> target, String fieldName, Object value) throws SecurityException, IllegalArgumentException, IllegalAccessException{
    		if(target == null) 
    			return null;
    		
    		if(target.getClass().equals(Object.class))
    			return null;
    		
    		Field field = null;
    		
    		try {
    			field = target.getDeclaredField(fieldName);
    			field.setAccessible(true);
    			
    		} catch (NoSuchFieldException e) {
    			searchSuperField(target.getSuperclass(), fieldName, value);
    		}
    		
    		if(field != null) {
    			field.set(null, value);
    		}
    		return target;
    	}
    

    注意:被注入的变量一定要是静态的。
    这只是思路,提升Activity的可测试性。
  • 给面向接口编程优点之一:提高可测试性。譬如说设计Mock的时候,安逸啊。。
  • 命令行下执行测试代码必备命令:adb shell pm(万恶的google文档,让我按照tutorial折腾了几个小时,也没有弄出来,结果SO上一个回答搞定。。可恶,##)。
  • 如果有命令不明白,去看InstrumentationTestRunner类的doc非常有帮助。
  • 设计良好的intent结构,能提高可测试性。单元测试、Instrumentation测试时,使用intent控制程序流程相当容易,monkey测试时更是如此。其实根据我第一个小demo的经验来看,最容易不写intent的地方就是activity的跳转控制,所以这可能是一个需要注意的地方。
  • //待续
    分享到:
    评论

    相关推荐

      redis 读写性能测试代码

      描述中提到的是“redis 写的操作性能测试代码”,那么具体的测试实现可能包括以下步骤: 1. **初始化环境**:启动Redis服务器,确保无其他应用占用资源,设置合适的服务器配置。 2. **编写测试代码**:使用Jedis...

      自己编写的测试代码

      在IT行业中,编写测试...总的来说,编写测试代码是软件开发中不可或缺的一部分,它有助于提高代码质量和维护性,确保最终产品的稳定性和可靠性。通过对各个层面的测试,开发者可以更有信心地交付满足需求的软件产品。

      手写识别测试代码

      卷积神经网络的数字识别手写测试代码 python3.5 准确率98% 取出模型 画板手写测试 字体颜色和背景相差大就行 字体不能太细 有编译代码可以看到数字样本图片

      自己写的测试代码

      "自己写的测试代码"这个标题和描述都暗示了我们正在讨论的是个人独立编写的用于验证程序功能的代码段。下面我们将深入探讨测试代码的相关知识点。 首先,测试代码的目的是验证程序的功能是否符合预期。这包括单元...

      德卡D8 读卡器读写CPU卡测试代码

      在进行“德卡D8读卡器读写CPU卡测试代码”时,我们主要关注以下几个关键知识点: 1. **硬件接口**:德卡D8读卡器通常通过USB接口与计算机连接。测试代码需要正确识别并初始化这个硬件设备,以便进行后续的数据传输...

      测试代码 C语言的测试代码

      在开发过程中,测试代码是不可或缺的一环,因为它确保了程序的正确性和可靠性。 测试代码的主要目的是验证程序的功能是否按照预期工作,并找出可能存在的错误或缺陷。C语言中的测试通常包括单元测试、集成测试和...

      极限编程编程新理念,先测试后写代码

      "先测试后写代码"是极限编程中的一个核心实践,被称为测试驱动开发(Test-Driven Development,TDD)。下面我们将深入探讨这一理念及其在实际编程过程中的应用。 **测试驱动开发(TDD)** 测试驱动开发是一种软件...

      读写分离源码及其测试代码

      读写分离插件的源码,其中db-router-test项目是测试项目代码,先 mvn install datasource-router-starter项目后可运行测试;源码解析:https://blog.csdn.net/weixin_47626220/article/details/117090788

      struts2学习测试代码

      struts2学习测struts2学习测试代码试代码

      AXI4协议测试代码

      在“AXI4协议测试代码”中,ARM官方提供了一套测试程序,旨在帮助开发者验证AXI4接口的正确性,并确保其在Transaction Level Modeling (TLM)环境中运行良好。 首先,我们来看“BP063-BU-01000-r0p1-00rel0.lst”。...

      测试驱动开发的艺术测试代码

      测试驱动开发(Test-Driven Development,简称TDD)是一种软件开发方法,强调在编写实际功能代码之前先编写测试代码。这种做法有助于确保软件的质量,减少bug,并提高代码的可维护性。在“测试驱动开发的艺术”中,...

      单元测试的代码覆盖率至少80%

      ”大师回答道:“不要考虑代码覆盖率,只要写出一些好的测试用例即可。”  一大早,一个年轻的程序员问大师:  “我准备写一些单元测试用例。代码覆盖率应该达到多少为好?”  大师回答道:  “不要考虑代码覆盖率...

      自己写的ssl测试代码

      在您提供的"自己写的ssl测试代码"中,我们可以推测这是一个用于验证或调试SSL连接的程序。编写这样的代码可以帮助理解SSL的工作原理,检查SSL证书的有效性,以及确保服务器与客户端之间的通信符合安全标准。 SSL...

      对基于Junit的测试代码自动化生成的研究

      2. **测试驱动开发(TDD)**:TDD是一种软件开发实践,提倡先写测试,再写实现代码。在基于Junit的自动化测试中,TDD可以帮助开发者确保新添加的代码符合预期,并减少回归错误。 3. **自动化测试生成**:研究可能探讨...

      29丨理论三:什么是代码的可测试性?如何写出可测试性好的代码?1

      【如何写出可测试的代码】: 1. **低耦合**:减少类与类之间的依赖,比如使用接口而非具体实现,使测试能独立于其他组件进行。 2. **高内聚**:确保每个类或方法专注于单一任务,这样测试可以更精确地针对特定功能。...

      测试的一些demo代码

      在IT行业中,编写和测试代码是开发者日常工作中不可或缺的部分。"测试的一些demo代码"这个标题表明,这是一些用于测试目的的示例代码,可能是为了验证某个功能、修复bug或者理解新概念。这类代码通常简洁明了,易于...

      我自己写的一些测试代码

      例如,使用TDD(测试驱动开发)方法,先写测试再写功能代码;每个测试用例应独立,不依赖其他测试;测试应该可重复且覆盖所有可能的输入情况;最后,要定期运行自动化测试,确保代码的持续健康。 为了进一步提高...

      pafa4 测试代码

      在IT行业中,"pafa4 测试代码"可能是指一个特定的软件开发项目或框架的测试部分,这里的“pafa4”可能是项目名或者是自定义的版本标识。这个压缩包文件包含了与“pafa4”相关的测试代码,旨在帮助开发者进行功能验证...

      aaa.rar_代码_测试_测试代码

      测试驱动开发(TDD)和行为驱动开发(BDD)是两种流行的开发模式,它们强调先写测试再编写实现代码,有助于提升代码质量。 在压缩包"aaa.rar"中,如果包含的是一个完整的项目,那么我们可能找到以下内容: 1. 源...

    Global site tag (gtag.js) - Google Analytics