Android测试驱动开发实践2

在实际项目开发过程中,一般先实现核心功能,最后再做辅助性功能,这样可以尽快验证Idea的正确性,同时有助于让老板、投资人或客户看到可运行的产品,从而对产品充满信心,加大对项目的支持。

  但是对于我们这个项目而言,我们首先需要得到一个Android应用MVC的架构体系,因此我们首先来实现一些典型功能,但是可以完整体现MVC架构的功能。在此我们选择任何应用程序在启动时都会显示的Splash页面,通常这个页面会显示一个应用图片,过30秒左右再显示程序的主界面,应用在这段时间完成数据加载等准备工作

  在这里我们要稍微背离一下测试驱动开发的标准方法,原因是我们在进行Android应用开发,由于Android系统限制有很多方面是很难做单元测试的,硬做单元测试,除了理论上的有效性外,没有任何实际意义。

  在这里,我们采用验收测试驱动开发的理念,即我们开发足够功能来满足一个验收测试用例。这里我们选择的一个验收测试用例为:应用在开启时,先显示10秒应用图片,然后自动进入应用首页,也就是我们通常所看到的Splash屏幕功能。

  我们首先定义SplashActivity类,代码如下所示:


package com.bjcic.wkj;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.view.WindowManager;

public class SplashActivity extends Activity {

// 生命周期方法---开始

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//全屏

setContentView(R.layout.splash);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);

appModel = (AppModel)getApplication();

appController = appModel.getAppController();

appController.postDelayed(new Runnable() {

/**

* 隔10秒钟启动主页面

*/

@Override

public void run() {

appController.processEvent(new AppEvent(SplashActivity.this, AppEvent.EVE_SPLASH_END, null));

}

}, AppKeys.SPLASH_DURATION);

// 启动异步任务准备应用数据

}

// 生命周期方法---结束

private AppController appController = null;

private AppModel appModel = null;

}

这个Activity所对应的布局文件为:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:background="@drawable/splash">

</LinearLayout>

  布局文件就是定义了一下Splash屏幕的背景图。

  这里我们引入了AppController类,是应用的控制器类。Activity中用户的操作和系统的状态改变都会生成相应的事件,由AppController.processEvent来进行统一处理,同时异步任务、线程等产生的需要界面更新的操作,通过向AppController发送Message来实现(因为AppController继承了Handler类)。具体代码如下所示:


package com.bjcic.wkj;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

public class AppController extends Handler {

public AppController(AppModel appModel) {

super();

this.appModel = appModel;

}

/**

* Activity中会根据用户的操作或系统状态,产生对应的事件,发送给AppController进行统一处理。

* @param event

*/

public void processEvent(AppEvent event) {

switch (event.getEventId()) {

case AppEvent.EVE_SPLASH_END: // 从Splash界面显示主界面

showMainActivity((Activity)event.getContext(), event.getParams());

break;

default:

break;

}

}

/**

* 异步任务、线程、后台服务等需要更新界面时,向AppController发送消息即可

*/

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

}

/**

* 关闭Splash页面并打开应用主界面

* @param activity

* @param params

*/

private void showMainActivity(Activity activity, Bundle params) {

Log.d("wkj", "activity=" + activity + "; c=" + MainActivity.class + "!");

Intent intent = new Intent(activity, MainActivity.class);

activity.startActivity(intent);

activity.finish();

}

private AppModel appModel = null;

}

 在上面的代码中,事件处理函数直接写在的应用总的Controller中,其实也可以写到具体的Controller中,为了代码的可维护性,最好还是将事件处理写到对应模块的Controller中比较好。

  下面就是AppEvent的定义:


package com.bjcic.wkj;

import android.content.Context;

import android.os.Bundle;

public class AppEvent {

public AppEvent(Context context, int eventId, Bundle params) {

this.context = context;

this.eventId = eventId;

this.params = params;

}

public Context getContext() {

return context;

}

public void setContext(Context context) {

this.context = context;

}

public Bundle getParams() {

return params;

}

public int getEventId() {

return eventId;

}

public void setEventId(int eventId) {

this.eventId = eventId;

}

public final static int EVE_NONE = 0;

public final static int EVE_SPLASH_END = 1; // Splash界面显示时间到期

private Context context = null;

private int eventId = 0;

private Bundle params = null;

}

  在上面的事件定义中,事件中包含当前的Activity,事件ID和事件参数,这样AppController就可以直接对事件进行处理了。

  最后,我们在Splash页面停留10秒,这里需要定义一个常量,我们将应用中需要用到的重要常量,统一定义到AppKeys中,如下所示:


package com.bjcic.wkj;

public class AppKeys {

public final static long SPLASH_DURATION = 10 * 1000;

}

  好的,现在可以运行这个应用程序了,如果一切正常,应该可以看到一个Splash页面显示10秒钟后,进入到程序主界面中。至此我们的第一个验收测试用例就顺利通过了。

  这时,我们再回到WkjTest这个工程中,以Android Junit形式运行MainActivityTest,这时应该显示所有测试用例全部通过。

  注:大家也许注意到了,测试驱动开发是以一小步一小步的开发测试为基础的,在实际工作中,有一半愉上的程序员喜欢先把所有代码写好,然后在进行调试。当然也有一部分开发人员写一点调一点,这纯属于习惯性问题,不存在孰优孰劣的问题。但是采用测试驱动开发方法学,就要采用后面的工作方式。

  因此,测试驱动开发不一定适合所有人,对于喜欢一次性先把代码写好,然后进行调试的人来说,让他们接受测试驱动开发的工作方式是很困难的,这一点希望大家能够重视起来。

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-09-09 20:58:28

Android测试驱动开发实践2的相关文章

Android测试驱动开发实践1

在正式进行Android测试驱动开发之前,不得不先提一下Android应用架构问题.在传统软件开发中,MVC架构得到了广泛的应用,然而在Android开发中,很少见应用采用了MVC架构(不要说Android及Widget全部采用的是MVC架构,那是系统的事,我们讲的是应用程序开发),究其原因可能是初期Android应用大多较为简单,没有采用的必要,而后期一直在沿用初期的习惯.但是遇到一些复杂的应用,例如同样的数据在多个Activity中显示,如果数据分散在多个Activity中,那么数据发生更新

Android测试驱动开发实践

在Android应用开发中,相信很少有人在坚持先由设计人员做完整的概要设计 .详细设计,然后交给程序员进行编码实现了.通常是在有一个大体框架的情况下,就开始进行具体编码开发了.在这种情形下,开发速度可以有很大的提高,但是最终代码质量却不可避免的降低了.如何能既保持开发速度,同时又能保证开发质量呢?相信测试驱动开发是一种比较可行的开发方法学. 测试驱动开发首先通过设计测试用例,对从用户需求到方法接口进行细化,在构想这些测试用例的过程,就是站在使用者角度上来思考系统的过程,而传统方法中设计人员通常是

测试驱动开发实践之重构篇

前一篇文章 测试驱动开发实践-入门篇 我们我们讲了一些基本的测试驱动开发流程: 1.写单元测试使他亮红灯 2.写代码使测试变成绿灯 3.重构代码 接下来我们需要开始重构了,大家有可能会问,为什么需要重构,什么时候开始重构. 对与为什么需要重构,其实就是为了使代码结构清晰,去除一些重复的代码,比如我们执行sql语句操作,我们起初这样写 Code 1private connStr="server=.;database=TestDB;uid=sa;pwd=123" 2public int A

Android 开发之旅:短信的收发及在android模拟器之间实践(二)

引言 前面我们介绍都只是如何发送SMS消息,接下来我们介绍如何接收SMS消息,及另一种发短信的方式并增强为可以发生图片等,最后介绍一下emulator工具.本文的主要内容如下: 1~5见Android 开发之旅:短信的收发及在android模拟器之间实践(一) 6.温故知新之Intent 7.准备工作:SmsMessage类 8.SMS接收程序 9.另一种发送短信的方式:使用Intent 10.增强SMS为MMS 6.温故知新之Intent 此系列前面简单地接受过意图(Intent),这里再次简

《重构与模式(修订版)》—第1章1.4节测试驱动开发和持续重构

1.4 测试驱动开发和持续重构 重构与模式(修订版) 测试驱动开发[Beck, TDD]和持续重构,是极限编程诸多优秀实践中的两个,它们彻底改进了我开发软件的方式.我发现,这两个实践能够帮助我和公司降低过度设计和设计不足的几率,将时间用在按时地构造出高质量.功能丰富的代码上. 通过测试驱动开发(TDD)和持续重构,我们将编程变成一种对话1,从而高效地使可以工作的代码不断演变. 问:编写一个测试,向系统提问. 答:编写代码通过这个测试,回答这一提问. 提炼:通过合并概念.去芜存菁.消除歧义,提炼你

详尽讲述用Python的Django框架测试驱动开发的教程_python

测试驱动开发(TDD)是一个迭代的开发周期,强调编写实际代码之前编写自动化测试. 这个过程很简单:     先编写测试.     查看测试失败的地方     编写足够的代码以使测试通过.     再次测试.     代码重构 .     重复以上操作. 为什么要用TDD? 使用TDD,你将学会把你的代码拆分成符合逻辑的,简单易懂的片段,这有助于确保代码的正确性. 这一点非常重要,因为做到下面这些事情是非常困难的:     在我们的脑中一次性处理所有复杂的问题.     了解何时从哪里开始着手解决

测试驱动开发(TDD)的思考

极限编程   敏捷开发是一种思想,极限编程也是一种思想,它与敏捷开发某些目标是一致的.只是实现方式不同.测试驱动开发是极限编程的一部分.   1.极限编程这个思路的来源     Kent Beck先生最早在其极限编程(XP)方法论中,向大家推荐"测试驱动"这一最佳实践,还专门撰写了<测试驱动开发>一书,详细说明如何实现.经过几年的迅猛发展,测试驱动开发已经成长为一门独立的软件开发技术,其名气甚至盖过了极限编程.[1]     2.为什么测试驱动开发在实践中难以开展   测试

extension-关于android里面发邮件的问题,下面是我运行时候的log,请各位帮我看一下。

问题描述 关于android里面发邮件的问题,下面是我运行时候的log,请各位帮我看一下. 04-07 14:06:05.294: I/System.out(2970): DEBUG: JavaMail version 1.4.104-07 14:06:05.294: I/System.out(2970): DEBUG: not loading file: /system/lib/javamail.providers04-07 14:06:05.298: I/System.out(2970):

用NUnit2.1简单实现.net的测试驱动开发(TDD)

用NUnit2.1简单实现.net的测试驱动开发(TDD)下面的例子很简单,就是实现两个整数的四则运算,TDD提倡测试优先,即先写测试用例,再写运行代码,刚下了个NUnit2.1,迫不及待的试了试--1最初的测试用例using System;using NUnit.Framework;namespace netshop{ /// <summary> /// 四则运算TestCls测试用例 /// Edit by spgoal /// </summary> [TestFixture]