目录
在实际开发中,开发android软件的过程需要不断地进行测试。而使用Junit测试框架,侧是正规Android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性。
首先建立一个新的Android项目,这里我命名为:junit,然后编写AndroidManifest.xml文件,在里面添加uses-library和instrumentation两个属性,代码如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="lq.wangzhen.junit" android:versionCode="1" android:versionName="1.0" > <instrumentation android:name="android.test.InstrumentationTestRunner" android:label="Tests for My App" android:targetPackage="lq.wangzhen.junit" /> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <uses-library android:name="android.test.runner" /> <activity android:name="lq.wangzhen.junit.DemoActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
其中在instrumentation中配置的targetPackage为测试类所在的包,我这里的包名为:lq.wangzhen.junit
编写完以上的代码以后,则可以在lq.wangzhen.junit包中定义一个类,这个类中包含一个Add方法,然后我们进行此方法的测试工作。代码如下:
Services.java
package lq.wangzhen.junit; public class Service { /** * 提供一个方法,可以接收两个整型数据 * @param x * @param y * @return */ public static int add(int x,int y){ return x+y; } }
下面编写测试类,此类命名为:TestAddService.java,此类必须要集成AndroidTestCase才能够作为测试类进行使用,代码如下:
package lq.wangzhen.junit; import junit.framework.Assert; import android.test.AndroidTestCase; public class TestAddService extends AndroidTestCase { public void testAdd(){ int result = Service.add(3, 5); Assert.assertEquals(8, result); } }
以上就是一个简单的Android测试过程
完成完以上的测试功能后,下面我们来完成一个简单的用户登陆功能,现在要求用户输入用户名和密码,并选择是否保存用户名和密码,如果保存用户名和密码的话,我们要在ROM进行保存,然后在用户下次打开此软件时会自动的从文件中提取出对应的用户名和密码,填入到登陆框中,在本节中就先对界面进行一下设计,界面设计的xml文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/username" /> <EditText android:id="@+id/et_username" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/username" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/password" /> <EditText android:id="@+id/et_password" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/password" android:inputType="textPassword" /> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/login" android:layout_alignParentLeft="true"/> <CheckBox android:id="@+id/cb_remember" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/remember_password" android:layout_alignParentRight="true"/> </RelativeLayout> </LinearLayout>
下面开始编写MainActivity.java文件,代码如下:
package lq.wangzhen.file; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private static final String TAG = "MainActivity"; private EditText et_username; private EditText et_password; private Button button; private CheckBox cb_remember; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_username = (EditText) this.findViewById(R.id.et_username); et_password = (EditText) this.findViewById(R.id.et_password); button = (Button) this.findViewById(R.id.button); cb_remember = (CheckBox) this.findViewById(R.id.cb_remember); button.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.button: String username = et_username.getText().toString().trim(); String password = et_password.getText().toString().trim(); if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){ Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show(); return; } if(cb_remember.isChecked()){ Log.i(TAG, "保存用户名和密码,"+username+":"+password); }else{ Log.i(TAG, "没有保存用户名和密码,"+username+":"+password); } break; } } }
以上程序所使用的strings.xml文件的内容如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <string name="app_name">file</string> 5 <string name="hello_world">Hello world!</string> 6 <string name="menu_settings">Settings</string> 7 8 <string name="username">用户名</string> 9 <string name="password">密码</string> 10 <string name="login">登陆</string> 11 <string name="remember_password">记住密码</string> 12 <string name="error">用户名和密码不能为空</string> 13 14 </resources>
下面对以上的程序进行修改,加入可以将用户名和代码保存到文件中的功能,首先新建立一个Service文件,用来操作文件的保存,代码如下:
package lq.wangzhen.service; import java.io.FileOutputStream; import android.content.Context; public class FileService { private Context context; public FileService(Context context){ this.context = context; } /** * 把用户名和密码保存到手机ROM * @param password 输入要保存的密码 * @param username 要保存的用户名 * @param filename 保存到哪个文件 * @return */ public boolean saveToRom(String password,String username,String filename) throws Exception{ //以私有的方式打开一个文件 FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE); String result = username+":"+password; fos.write(result.getBytes()); fos.flush(); fos.close(); return true; } }
修改MainActivity.java文件,代码如下:
package lq.wangzhen.file; import lq.wangzhen.service.FileService; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private static final String TAG = "MainActivity"; private EditText et_username; private EditText et_password; private Button button; private CheckBox cb_remember; private FileService fileService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_username = (EditText) this.findViewById(R.id.et_username); et_password = (EditText) this.findViewById(R.id.et_password); button = (Button) this.findViewById(R.id.button); cb_remember = (CheckBox) this.findViewById(R.id.cb_remember); button.setOnClickListener(this); //初始化文件服务 fileService = new FileService(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.button: String username = et_username.getText().toString().trim(); String password = et_password.getText().toString().trim(); if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){ Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show(); return; } if(cb_remember.isChecked()){ Log.i(TAG, "保存用户名和密码,"+username+":"+password); try { boolean result = fileService.saveToRom(password, username, "private.txt"); if(result){ Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(getApplicationContext(), R.string.failed, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Toast.makeText(getApplicationContext(), R.string.failed, Toast.LENGTH_SHORT).show(); } } break; } } }
在strings.xml文件中添加以下的内容:
1 <string name="success">保存成功</string> 2 <string name="failed">保存失败</string>
运行程序,即可保存成功,保存的文件默认的保存在data/data/lq.wangzhen.file/files文件夹中,其中lq.wangzhen.file表示Activity所在的包名。下面在此程序的基础上加入可以从文件中读取用户名和密码的功能,首先在FileService.java文件中添加以下的一个方法,用来从ROM中读取文件内容。
public Map<String,String> getUserInfo(String filename) throws Exception{ File file = new File("data/data/lq.wangzhen.file/files/"+filename); FileInputStream fis = new FileInputStream(file); //以上的两句代码也可以通过以下的代码实现: //FileInputStream fis = context.openFileInput(filename); byte[] data = StreamTools.getBytes(fis); String result = new String(data); String results[] = result.split(":"); Map<String,String> map = new HashMap<String,String>(); map.put("username", results[0]); map.put("password", results[1]); return map; }
在此方法中调用了一个StreamTools.getBytes()方法,此方法是专门用来将一个InputStream流转换为byte数组返回的,所以我们编写此方法为:
package lq.wangzhen.util; import java.io.ByteArrayOutputStream; import java.io.InputStream; public class StreamTools { /** * 把InputStream中的内容读出来,放到一个byte[]中返回 * @param is * @return * @throws Exception */ public static byte[] getBytes(InputStream is) throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len=is.read(buffer)) != -1){ baos.write(buffer, 0, len); } baos.flush(); baos.close(); return baos.toByteArray(); } }
最后再次修改MainActivity.java文件,调用编写的getUserInfo方法:
package lq.wangzhen.file; import java.util.Map; import lq.wangzhen.service.FileService; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private static final String TAG = "MainActivity"; private EditText et_username; private EditText et_password; private Button button; private CheckBox cb_remember; private FileService fileService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_username = (EditText) this.findViewById(R.id.et_username); et_password = (EditText) this.findViewById(R.id.et_password); button = (Button) this.findViewById(R.id.button); cb_remember = (CheckBox) this.findViewById(R.id.cb_remember); button.setOnClickListener(this); //初始化文件服务 fileService = new FileService(this); try { Map<String,String> map = fileService.getUserInfo("private.txt"); et_username.setText(map.get("username")); et_password.setText(map.get("password")); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.button: String username = et_username.getText().toString().trim(); String password = et_password.getText().toString().trim(); if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){ Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show(); return; } if(cb_remember.isChecked()){ Log.i(TAG, "保存用户名和密码,"+username+":"+password); try { boolean result = fileService.saveToRom(password, username, "private.txt"); if(result){ Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(getApplicationContext(), R.string.failed, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Toast.makeText(getApplicationContext(), R.string.failed, Toast.LENGTH_SHORT).show(); } } break; } } }