有种情况,我们开发人员可能要对已经完成的应用做维护,其中某个界面可能存在bug,所以为了测试某个可能存在问题的功能界面而从入口一直开始跳至该界面,这个情况,我们测试人员可以自己不停的跳过一些非测试目的界面,浪费了时间。这里有个小的方式,是android提供的系统测试方案,可以来试试,今天我试了试Activity的单独测试方式,感觉还不错,在这里分享给各位。
首先模拟一个我们要被测的项目:TestActivity和主要测试的登陆界面
需要测试的功能是,模拟用户输入,并登陆操作,以及重置功能的操作验证。好,看我们下面怎么实现吧
1.首先看看模拟项目中的代码,就2个简单的文件,一个模拟登陆的主界面,一个登陆后跳转界面。
MainActivity.java
/** * 登陆主界面,模拟的demo * @author jan */ public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity"; private EditText mLoginName; private EditText mPwd; private Button mLoginButton; private Button mRestButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mLoginName = (EditText) findViewById(R.id.login_name_et); mPwd = (EditText) findViewById(R.id.pwd_et); mLoginButton = (Button) findViewById(R.id.login); mRestButton = (Button) findViewById(R.id.reset); mLoginButton.setOnClickListener(this); mRestButton.setOnClickListener(this); } @Override protected void onDestroy() { super.onDestroy(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.login: login(); break; case R.id.reset: reset(); break; } } /** * 登陆,没有实际的验证等操作,这里就是跳转到另一个界面 */ private void login(){ Intent intent = new Intent(MainActivity.this,ResultActivity.class); intent.putExtra("name", mLoginName.getText().toString()); intent.putExtra("pwd", mPwd.getText().toString()); startActivity(intent); } /** * 重置,清除所有输入 */ private void reset(){ mLoginName.setText(""); mPwd.setText(""); } }ResultActivity.java
public class ResultActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.result); Intent get = getIntent(); String name = get==null?"":get.getStringExtra("name"); String pwd = get == null?"":get.getStringExtra("pwd"); ((EditText)findViewById(R.id.name_et)).setText(name); ((EditText)findViewById(R.id.pwd_et)).setText(pwd); } }
2.创建测试项目,在package Explorer区右键New->点击Progect,弹出选项选中Android:Android Test Progec-点击Next->输入单元测试项目名称progect name->点击Next->选择被测项目(本例中的TestActivity.->finish.
3.创建完成后,可以看看这个空的项目是什么特别之处,看AndroidManifest.xml,原来是导入了android的测试环境
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.testactivity.test" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.testactivity" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <uses-library android:name="android.test.runner" /> </application> </manifest>4.创建我的测试类,针对MainActivity的MainActivityTest类,继承了ActivityInstrumentationTestCase2,该类是可以单独测试App中的某个界面。
/** * MainActivity的测试类 * @author jan */ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> { private MainActivity mActivity; private Instrumentation mInstrumentation; private EditText nameEt; private EditText pwdEt; private Button loginButton; private Button resetButton; public MainActivityTest() { super(MainActivity.class); } //初始设置 @Override protected void setUp() throws Exception { super.setUp(); Log.i("MainActivityTest", "---setUp---"); //避免手动触摸的情况,关闭TouchMode setActivityInitialTouchMode(false); mInstrumentation = getInstrumentation(); //获取被测的Activity mActivity = getActivity(); //获取这个活动界面的控件 nameEt = (EditText) mActivity .findViewById(com.example.testactivity.R.id.login_name_et); pwdEt = (EditText) mActivity .findViewById(com.example.testactivity.R.id.pwd_et); loginButton = (Button) mActivity .findViewById(com.example.testactivity.R.id.login); resetButton = (Button) mActivity .findViewById(com.example.testactivity.R.id.reset); } //测试:确保每个控件都不为空 public void testPreCondition() { assertNotNull(mActivity); assertNotNull(nameEt); assertNotNull(pwdEt); assertNotNull(loginButton); assertNotNull(resetButton); } public void input() { //通过这个方式在UI上模拟点击的事件 mActivity.runOnUiThread(new Runnable() { @Override public void run() { nameEt.requestFocus(); nameEt.performClick(); } }); //等待被测试的应用程序的主线程 与 测试用例的线程 同步,大概是这个意思吧 mInstrumentation.waitForIdleSync(); //模拟输入 测试数据的键值 sendKeys(KeyEvent.KEYCODE_T, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_T, KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_E); mActivity.runOnUiThread(new Runnable() { @Override public void run() { pwdEt.requestFocus(); pwdEt.performClick(); } }); sendKeys(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3, KeyEvent.KEYCODE_4, KeyEvent.KEYCODE_5); } public void testInput(){ input(); //测试输入的值与预测的内容是否一致 assertEquals("testname",nameEt.getText().toString()); assertEquals("12345", pwdEt.getText().toString()); } /** * 测试登陆的功能 */ public void testLogin(){ input(); mInstrumentation.runOnMainSync(new Runnable() { @Override public void run() { loginButton.requestFocus(); loginButton.performClick(); } }); } /** * 测试重置按钮的功能 */ public void testReset(){ input(); mInstrumentation.runOnMainSync(new Runnable() { @Override public void run() { resetButton.requestFocus(); resetButton.performClick(); } }); assertEquals("", nameEt.getText().toString()); assertEquals("", pwdEt.getText().toString()); } //用于对资源的回收和释放 @Override protected void tearDown() throws Exception { Log.i("MainActivityTest", "---tearDown---"); super.tearDown(); } }同样的,还可以对ResultActivity这么做:
public class ResultActivityTest extends ActivityInstrumentationTestCase2<ResultActivity> { private ResultActivity resultActivity; private EditText nameEt,pwdEt; public ResultActivityTest(){ super(ResultActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); //创建Intent,通过Intent传递用户的登录信息 Intent intent = new Intent(); intent.putExtra("name", "helloworld"); intent.putExtra("pwd", "123456"); //通过携带用户登录信息的intent启动FxResultActivity resultActivity = launchActivityWithIntent("com.example.testactivity", ResultActivity.class, intent); //获取UI组件 nameEt = (EditText)resultActivity.findViewById(com.example.testactivity.R.id.name_et); pwdEt = (EditText)resultActivity.findViewById(com.example.testactivity.R.id.pwd_et); } public void testLoginInfo(){ assertEquals("helloworld", nameEt.getText().toString()); assertEquals("123456", pwdEt.getText().toString()); } }5.你可以运行他了,选中要运行的ActivityTest,右键Run as ->Android Junit Test ,然后就看他的无手动操作的测试,方法是顺序执行的,可能你会发现执行完testLogin后就不执行下去了,那是因为他已经跳转到另一个界面,所以测试其他的方法可以先屏蔽掉testLogin即可。
好了,这只是一个小技巧,实际中用到的并不多,只需了解即可,当然有兴趣的可以试试看