【正文】
一、单元测试的引入:
如果只是普通的一个小程序,编写测试是有些多此一举,但是当项目比较庞大的时候,一般都应该去编写单元测试。JUnit测试是白盒测试,即主要是程序员自己对开发的方法进行功能性测试。JUnit是一套框架,Android中也沿用了这一套框架。
在Android中使用JUnit测试大致分如下几个步骤:
- (1)在AndroidManifest.xml中增加对JUnit的支持,并制定测试项目包。
- (2)在AndroidManifest.xml中<application.../>节点中增加一个<uses-library...>节点,name属性为android.test.runner。
- (3)在编写待测试方法后,新建一个类,继承AndroidTestCase,在其中编写测试用例代码。
- (4)鼠标左键在测试用例方法上,Run As→Android JUnit Test。
二、步骤详解:
(1)配置清单文件:
新建Android工程文件,命名为m05_SharedPreferencesTest,
首先在AndroidManifest.xml添加一个Instrumentation:
指定Instrumentation的name与TargetPackage:
然后保存。
紧接着在<application.../>节点中增加<uses-library android:name="android.test.runner" />。
完成后,AndroidManifest.xml代码如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.m05_sharedpreferencestest" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="8" 9 android:targetSdkVersion="16" /> 10 11 <instrumentation 12 android:name="android.test.InstrumentationTestRunner" 13 android:targetPackage="com.example.m05_sharedpreferencestest" > 14 </instrumentation> 15 16 <application 17 android:allowBackup="true" 18 android:icon="@drawable/ic_launcher" 19 android:label="@string/app_name" 20 android:theme="@style/AppTheme" > 21 <uses-library android:name="android.test.runner" /> 22 23 <activity android:name="com.example.m05_sharedpreferencestest.MainActivity" 24 android:label="@string/app_name" > 25 <intent-filter> 26 <action android:name="android.intent.action.MAIN" /> 27 28 <category android:name="android.intent.category.LAUNCHER" /> 29 </intent-filter> 30 </activity> 31 </application> 32 33 </manifest>
上方11至14行以及21行是我们所添加的代码。
编写一个类,我们需要做的是在里面实现记住密码的功能:
通过SharedPreferences保存用户输入的用户名、密码:
package com.example.m05_sharedpreferencestest; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; public class LoginService { private Context context; //为了获取SharedPreferences这个类,我们需要一个上下文对象 public LoginService(Context context) { // TODO Auto-generated constructor stub this.context = context; } //方法:通过SharedPreferences保存用户输入的用户名、密码 public boolean saveLoginMsg(String name,String pwd) { boolean flag = false; SharedPreferences sp = context.getSharedPreferences("login", 0); Editor editor = sp.edit(); editor.putString("username", name); editor.putString("password", pwd); flag = editor.commit(); return flag; } }
编写一个测试类,这个类需要继承AndroidTestCase,针对上面的方法进行测试:
package com.example.m05_sharedpreferencestest; import android.test.AndroidTestCase; import android.util.Log; public class Mytest extends AndroidTestCase { public Mytest() { // TODO Auto-generated constructor stub } public void save(){ LoginService loginService = new LoginService(getContext()); boolean flag = loginService.saveLoginMsg("smyhvae", "smyh"); //如果数据保存成功,saveLoginMsg()方法将返回true值。 Log.i("Mytest", ""+flag); } }
现在来运行单元测试中的这个方法。右键选中save()方法,选中run as -->Android JUnit Test:
当执行成功后,会显示绿色,如果是其他颜色,则出错:
我们同样也能在login.xml文件中查看到内容:
我们刚刚保存的只是字符串类型。如果想要保存任何数据类型,可以在LoginService.java中添加如下方法:
public boolean saveSharePreference(String fileName, Map<String, Object> map) { boolean flag = false; SharedPreferences preferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); Editor editor = preferences.edit(); for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object object = entry.getValue(); if (object instanceof Boolean) { Boolean new_name = (Boolean) object; editor.putBoolean(key, new_name); } else if (object instanceof Integer) { Integer integer = (Integer) object; editor.putInt(key, integer); } else if (object instanceof Float) { Float f = (Float) object; editor.putFloat(key, f); } else if (object instanceof Long) { Long l = (Long) object; editor.putLong(key, l); } else if (object instanceof String) { String s = (String) object; editor.putString(key, s); } } flag = editor.commit(); return flag; }
运行单元测试后,msg.xml中的内容如下:
我们既然将数据存进去了,然后想将它读出来。需要再增加一个方法。代码实现见下面的内容。
【代码汇总】
总的来说,完整版代码如下:
LoginService.java代码如下:
1 package com.example.m05_sharedpreferencestest; 2 3 import java.util.Map; 4 import android.content.Context; 5 import android.content.SharedPreferences; 6 import android.content.SharedPreferences.Editor; 7 8 public class LoginService { 9 10 private Context context; //为了获取SharedPreferences这个类,我们需要一个上下文对象 11 public LoginService(Context context) { 12 // TODO Auto-generated constructor stub 13 this.context = context; 14 } 15 16 //方法:通过SharedPreferences保存用户输入的用户名、密码(字符串类型) 17 public boolean saveLoginMsg(String name,String pwd) { 18 boolean flag = false; 19 SharedPreferences sp = context.getSharedPreferences("login", 0); 20 Editor editor = sp.edit(); 21 editor.putString("username", name); 22 editor.putString("password", pwd); 23 flag = editor.commit(); 24 return flag; 25 } 26 27 //方法:通过SharedPreferences保存用户输入的用户名、密码(各种数据类型) 28 public boolean saveSharePreference(String fileName, Map<String, Object> map) { 29 boolean flag = false; 30 SharedPreferences preferences = context.getSharedPreferences(fileName, 31 Context.MODE_PRIVATE); 32 Editor editor = preferences.edit(); 33 for (Map.Entry<String, Object> entry : map.entrySet()) { 34 String key = entry.getKey(); 35 Object object = entry.getValue(); 36 if (object instanceof Boolean) { 37 Boolean new_name = (Boolean) object; 38 editor.putBoolean(key, new_name); 39 } else if (object instanceof Integer) { 40 Integer integer = (Integer) object; 41 editor.putInt(key, integer); 42 } else if (object instanceof Float) { 43 Float f = (Float) object; 44 editor.putFloat(key, f); 45 } else if (object instanceof Long) { 46 Long l = (Long) object; 47 editor.putLong(key, l); 48 } else if (object instanceof String) { 49 String s = (String) object; 50 editor.putString(key, s); 51 } 52 } 53 flag = editor.commit(); 54 return flag; 55 } 56 57 //方法:数据存储之后,然后读出来 58 public Map<String, ?> getSharePreference(String fileName) { 59 Map<String, ?> map = null; 60 SharedPreferences preferences = context.getSharedPreferences(fileName, 61 Context.MODE_PRIVATE); 62 map = preferences.getAll(); 63 return map; 64 } 65 66 }
MyTest.java代码如下:
1 package com.example.m05_sharedpreferencestest; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import android.test.AndroidTestCase; 7 import android.util.Log; 8 9 public class Mytest extends AndroidTestCase { 10 11 private final String TAG = "Mytest"; 12 public Mytest() { 13 // TODO Auto-generated constructor stub 14 } 15 16 public void save(){ 17 LoginService loginService = new LoginService(getContext()); 18 boolean flag = loginService.saveLoginMsg("smyhvae", "smyh"); 19 //如果数据保存成功,saveLoginMsg()方法将返回true值。 20 Log.d(TAG, ""+flag); 21 } 22 23 24 public void save2() { 25 LoginService service = new LoginService(getContext()); 26 Map<String, Object> map = new HashMap<String, Object>(); 27 map.put("name", "jack"); 28 map.put("age", 23); 29 map.put("salary", 3000.0f); 30 map.put("id", 1010010101l); 31 map.put("isManager", true); 32 boolean flag = service.saveSharePreference("msg", map); 33 Log.i(TAG, "--->>" + flag); 34 } 35 36 37 public void read() { 38 LoginService service = new LoginService(getContext()); 39 Map<String, ?> map = service.getSharePreference("msg"); 40 Log.i(TAG, "--->" + map.get("name")); 41 Log.i(TAG, "--->" + map.get("age")); 42 Log.i(TAG, "--->" + map.get("salary")); 43 Log.i(TAG, "--->" + map.get("id")); 44 Log.i(TAG, "--->" + map.get("isManager")); 45 } 46 }
如果执行read()方法的单元测试,后台输出如下:
三、常见测试方法:
黑盒测试: 是以用户的角度,从输入数据与输出数据的对应关系出发进行测试的。
白盒测试: 又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。
单元测试: 又称模块测试,是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。
功能测试: 根据产品特性、操作描述和用户方案,测试一个产品的特性和可操作行为以确定它们满足设计需求。
压力测试: 主体向被观察者布置一定量任务和作业,借以观察个体完成任务的行为。
集成测试: 是单元测试的逻辑扩展。它的最简单的形式是:两个已经测试过的单元组合成一个组件,并且测试它们之间的接口
备注:黑盒测试,不看代码结构,从用户的角度测试功能,例如玩某一款游戏来测试。白盒测试:通过代码测试功能。