转Android工程 单元测试(二)

时间 : 14-09-10 栏目 : 未分类, 集成测试 作者 : noway 评论 : 0 点击 : 433 次

测试相关资源
让开发自动化: 用 Eclipse 插件提高代码质量http://www.ibm.com/developerworks/cn/java/j-ap01117/index.html代码测试覆盖率介绍:http://www.cnblogs.com/coderzh/archive/2009/03/29/1424344.html

学习android单元测试时遇到的一些问题:
1.开始以为单元测试一定要从程序的launch Activity,一步一步的跳转到所要测试的Activity能对其进行测试。
但实际上,我们可以从任意一个activity开始,对任意一个activity进行测试。

2.在运行单元测试之前,一定要先将要测试的程序安装到模拟器或真机上。

junit相关
android中的测试框架是扩展的junit3,所以在学习android中的单元测试签,可以先熟悉下junit3的使用,junit3要学习的东西应该并不多,就几页纸的东西。入门可以参考这个:http://android.blog.51cto.com/268543/49994

android单元测试框架中涉及的注解
@Suppress 可以用在类或这方法上,这样该类或者该方法就不会被执行
@UiThreadTest 可以用在方法上,这样该方法就会在程序的ui线程上执行
@LargeTest, @MediumTest, @SmallTest 用在方法上,标记所属的测试类型,主要是用于单独执行其中的某一类测试时使用。具体参考InstrumentationTestRunner类的文档。
@Smoke 具体用法还不清楚

android单元测试框架中涉及的一些类的uml

接下来我们以demo project来讲解如何使用android中的单元测试
主要包括了三个activity:
MainActivity:仅包含一个button,点击后就可以进入LoginActivity

LoginActivity:可以输入username, password,然后点击submit的话可进入HomeActivity,如果点击reset的话,输入的内容就会被清空

HomeActivity:在TextView中显示LoginActivity输入的内容

首先我们创建要测试的项目demo(使用了2.1)

MainActivity代码

Java代码  收藏代码
  1. public class MainActivity extends Activity {
  2.     private static final boolean DEBUG = true;
  3.     private static final String TAG = "-- MainActivity";
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         if (DEBUG) {
  7.             Log.i(TAG, "onCreate");
  8.         }
  9.         super.onCreate(savedInstanceState);
  10.         setContentView(R.layout.act_main);
  11.         View toLoginView = findViewById(R.id.to_login);
  12.         toLoginView.setOnClickListener(new View.OnClickListener() {
  13.             public void onClick(View view) {
  14.                 if (DEBUG) {
  15.                     Log.i(TAG, "toLoginView clicked");
  16.                 }
  17.                 Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
  18.                 startActivity(intent);
  19.             }
  20.         });
  21.     }
  22. }

MainActivity的布局文件

Xml代码  收藏代码
  1. <LinearLayout
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent"
  5. >
  6.     <Button
  7.         android:id="@+id/to_login"
  8.         android:layout_width="fill_parent"
  9.         android:layout_height="wrap_content"
  10.         android:layout_gravity="bottom"
  11.         android:text="to login" />
  12. </LinearLayout>

LoginActivity代码

Java代码  收藏代码
  1. public class LoginActivity extends Activity {
  2.     private static final boolean DEBUG = true;
  3.     private static final String TAG = "-- LoginActivity";
  4.     private EditText mUsernameView;
  5.     private EditText mPasswordView;
  6.     @Override
  7.     protected void onCreate(Bundle savedInstanceState) {
  8.         if (DEBUG) {
  9.             Log.i(TAG, "onCreate");
  10.         }
  11.         super.onCreate(savedInstanceState);
  12.         setContentView(R.layout.act_login);
  13.         mUsernameView = (EditText) findViewById(R.id.username);
  14.         mPasswordView = (EditText) findViewById(R.id.password);
  15.         View submitView = findViewById(R.id.submit);
  16.         submitView.setOnClickListener(new View.OnClickListener() {
  17.             public void onClick(View view) {
  18.                 if (DEBUG) {
  19.                     Log.i(TAG, "submitView clicked");
  20.                 }
  21.                 Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
  22.                 intent.putExtra(HomeActivity.EXTRA_USERNAME, mUsernameView.getText().toString());
  23.                 intent.putExtra(HomeActivity.EXTRA_PASSWORD, mPasswordView.getText().toString());
  24.                 startActivity(intent);
  25.             }
  26.         });
  27.         View resetView = findViewById(R.id.reset);
  28.         resetView.setOnClickListener(new View.OnClickListener() {
  29.             public void onClick(View view) {
  30.                 if (DEBUG) {
  31.                     Log.i(TAG, "resetView clicked");
  32.                 }
  33.                 mUsernameView.setText("");
  34.                 mPasswordView.setText("");
  35.                 mUsernameView.requestFocus();
  36.             }
  37.         });
  38.     }
  39. }

LoginActivity的布局文件

Xml代码  收藏代码
  1. <LinearLayout
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent"
  5.     android:orientation="vertical"
  6. >
  7.     <TextView
  8.         android:id="@+id/label_username"
  9.         android:layout_width="fill_parent"
  10.         android:layout_height="wrap_content"
  11.         android:text="username:" />
  12.     <EditText
  13.         android:id="@+id/username"
  14.         android:layout_width="fill_parent"
  15.         android:layout_height="wrap_content"
  16.         android:inputType="text" />
  17.     <TextView
  18.         android:id="@+id/label_password"
  19.         android:layout_width="fill_parent"
  20.         android:layout_height="wrap_content"
  21.         android:text="password:" />
  22.     <EditText
  23.         android:id="@+id/password"
  24.         android:layout_width="fill_parent"
  25.         android:layout_height="wrap_content"
  26.         android:inputType="textPassword" />
  27.     <Button
  28.         android:id="@+id/submit"
  29.         android:layout_width="fill_parent"
  30.         android:layout_height="wrap_content"
  31.         android:text="submit" />
  32.     <Button
  33.         android:id="@+id/reset"
  34.         android:layout_width="fill_parent"
  35.         android:layout_height="wrap_content"
  36.         android:text="reset" />
  37. </LinearLayout>

HomeActivity代码

Java代码  收藏代码
  1. public class HomeActivity extends Activity {
  2.     private static final boolean DEBUG = true;
  3.     private static final String TAG = "-- HomeActivity";
  4.     public static final String EXTRA_USERNAME = "yuan.activity.username";
  5.     public static final String EXTRA_PASSWORD = "yuan.activity.password";
  6.     @Override
  7.     protected void onCreate(Bundle savedInstanceState) {
  8.         if (DEBUG) {
  9.             Log.i(TAG, "onCreate");
  10.         }
  11.         super.onCreate(savedInstanceState);
  12.         Intent intent = getIntent();
  13.         StringBuilder sb = new StringBuilder();
  14.         sb.append("username:").append(intent.getStringExtra(EXTRA_USERNAME)).append("\n");
  15.         sb.append("password:").append(intent.getStringExtra(EXTRA_PASSWORD));
  16.         setContentView(R.layout.act_home);
  17.         TextView loginContentView = (TextView) findViewById(R.id.login_content);
  18.         loginContentView.setText(sb.toString());
  19.     }
  20. }

HomeActivity的布局文件

Xml代码  收藏代码
  1. <LinearLayout
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent"
  5. >
  6.     <TextView
  7.         android:id="@+id/login_content"
  8.         android:layout_width="fill_parent"
  9.         android:layout_height="wrap_content"
  10.         android:layout_gravity="center_vertical"
  11.         android:gravity="center"
  12.         android:textColor="#EEE"
  13.         android:textStyle="bold"
  14.         android:textSize="25sp" />
  15. </LinearLayout>

程序非常简单,接下来我们为demo创建单元测试工程demo_unittest

选择之前创建的工程demo,然后eclipse会自动帮我们设定api level,包名等。(测试用例的包名一般就是在要测试类的包名后加上test)

创建完后eclipse会自动为我们创建好所需的目录,Manifest.xml文件

接下来就是为要测试的类编写测试用例。关于要用哪个测试用例类,在第一张UML图中也做了简要的说明。
ActivityInstrumentationTestCase2:主要是用于进行activity的功能测试,和activity的交互测试,如activity间的跳转,ui的交互等。

ActivityInstrumentationTestCase:这个类现在已deprecated了,所以不许考虑。

SingleLaunchActivityTestCase:该测试用例仅掉用setUp和tearDown一次,而不像其它测试用例类一样,没调用一次测试方法就会重新调用一次setUp和tearDown。所以主要测试activity是否能够正确处理多次调用。

ActivityUnitTestCase:主要用于测试Activity,因为它允许注入MockContext和MockApplicaton,所以可以测试Activity在不同资源和应用下的情况。

还有Application等的测试用例比较简单,看uml图。如果觉得不够详细,可以参考sdk文档的dev guide和api reference。

MainActivityTest测试用例

Java代码  收藏代码
  1. public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
  2.     private static final String TAG = "=== MainActivityTest";
  3.     private Instrumentation mInstrument;
  4.     private MainActivity mActivity;
  5.     private View mToLoginView;
  6.   //必不可少的东西, 不要忘记
  7.     public MainActivityTest() {
  8.         super("yuan.activity", MainActivity.class);
  9.     }
  10.     @Override
  11.     public void setUp() throws Exception {
  12.         super.setUp();
  13.         mInstrument = getInstrumentation();
  14.         // 启动被测试的Activity
  15.         mActivity = getActivity();
  16.         mToLoginView = mActivity.findViewById(yuan.activity.R.id.to_login);
  17.     }
  18.     public void testPreConditions() {
  19.         // 在执行测试之前,确保程序的重要对象已被初始化
  20.         assertTrue(mToLoginView != null);
  21.     }
  22.     //mInstrument.runOnMainSync(new Runnable() {
  23.     //  public void run() {
  24.     //      mToLoginView.requestFocus();
  25.     //      mToLoginView.performClick();
  26.     //  }
  27.     //});
  28.     @UiThreadTest
  29.     public void testToLogin() {
  30.         // @UiThreadTest注解使整个方法在UI线程上执行,等同于上面注解掉的代码
  31.         mToLoginView.requestFocus();
  32.         mToLoginView.performClick();
  33.     }
  34.     @Suppress
  35.     public void testNotCalled() {
  36.         // 使用了@Suppress注解的方法不会被测试
  37.         Log.i(TAG, "method 'testNotCalled' is called");
  38.     }
  39.     @Override
  40.     public void tearDown() throws Exception {
  41.         super.tearDown();
  42.     }
  43. }

LoginActivityTest测试用例

Java代码  收藏代码
  1. public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
  2.     private static final String TAG = "=== LoginActivityTest";
  3.     private Instrumentation mInstrument;
  4.     private LoginActivity mActivity;
  5.     private EditText mUsernameView;
  6.     private EditText mPasswordView;
  7.     private View mSubmitView;
  8.     private View mResetView;
  9.     public LoginActivityTest() {
  10.         super("yuan.activity", LoginActivity.class);
  11.     }
  12.     @Override
  13.     public void setUp() throws Exception {
  14.         super.setUp();
  15.         /*
  16.          *  要向程序发送key事件的话,必须在getActivity之前调用该方法来关闭touch模式
  17.          * 否则key事件会被忽略
  18.          */
  19.         setActivityInitialTouchMode(false);
  20.         mInstrument = getInstrumentation();
  21.         mActivity = getActivity();
  22.         Log.i(TAG, "current activity: " + mActivity.getClass().getName());
  23.         mUsernameView = (EditText) mActivity.findViewById(yuan.activity.R.id.username);
  24.         mPasswordView = (EditText) mActivity.findViewById(yuan.activity.R.id.password);
  25.         mSubmitView = mActivity.findViewById(yuan.activity.R.id.submit);
  26.         mResetView = mActivity.findViewById(yuan.activity.R.id.reset);
  27.     }
  28.     public void testPreConditions() {
  29.         assertTrue(mUsernameView != null);
  30.         assertTrue(mPasswordView != null);
  31.         assertTrue(mSubmitView != null);
  32.         assertTrue(mResetView != null);
  33.     }
  34.     public void testInput() {
  35.         input();
  36.         assertEquals("yuan", mUsernameView.getText().toString());
  37.         assertEquals("1123", mPasswordView.getText().toString());
  38.     }
  39.     public void testSubmit() {
  40.         input();
  41.         mInstrument.runOnMainSync(new Runnable() {
  42.             public void run() {
  43.                 mSubmitView.requestFocus();
  44.                 mSubmitView.performClick();
  45.             }
  46.         });
  47.     }
  48.     public void testReset() {
  49.         input();
  50.         mInstrument.runOnMainSync(new Runnable() {
  51.             public void run() {
  52.                 mResetView.requestFocus();
  53.                 mResetView.performClick();
  54.             }
  55.         });
  56.         assertEquals("", mUsernameView.getText().toString());
  57.         assertEquals("", mPasswordView.getText().toString());
  58.     }
  59.     @Override
  60.     public void tearDown() throws Exception {
  61.         super.tearDown();
  62.     }
  63.     private void input() {
  64.         mActivity.runOnUiThread(new Runnable() {
  65.             public void run() {
  66.                 mUsernameView.requestFocus();
  67.             }
  68.         });
  69.         // 因为测试用例运行在单独的线程上,这里最好要
  70.         // 同步application,等待其执行完后再运行
  71.         mInstrument.waitForIdleSync();
  72.         sendKeys(KeyEvent.KEYCODE_Y, KeyEvent.KEYCODE_U,
  73.                 KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_N);
  74.         // 效果同上面sendKeys之前的代码
  75.         mInstrument.runOnMainSync(new Runnable() {
  76.             public void run() {
  77.                 mPasswordView.requestFocus();
  78.             }
  79.         });
  80.         sendKeys(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_1,
  81.                 KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3);
  82.     }
  83. }

HomeActivityTest测试用例

Java代码  收藏代码
  1. public class HomeActivityTest extends ActivityUnitTestCase<HomeActivity> {
  2.     private static final String TAG = "=== HomeActivityTest";
  3.     private static final String LOGIN_CONTENT = "username:yuan\npassword:1123";
  4.     private HomeActivity mHomeActivity;
  5.     private TextView mLoginContentView;
  6.     public HomeActivityTest() {
  7.         super(HomeActivity.class);
  8.     }
  9.     @Override
  10.     public void setUp() throws Exception {
  11.         super.setUp();
  12.         Intent intent = new Intent();
  13.         intent.putExtra(HomeActivity.EXTRA_USERNAME, "yuan");
  14.         intent.putExtra(HomeActivity.EXTRA_PASSWORD, "1123");
  15.         // HomeActivity有extra参数,所以我们需要以intent来启动它
  16.         mHomeActivity = launchActivityWithIntent("yuan.activity", HomeActivity.class, intent);
  17.         mLoginContentView = (TextView) mHomeActivity.findViewById(yuan.activity.R.id.login_content);
  18.     }
  19.     public void testLoginContent() {
  20.         assertEquals(LOGIN_CONTENT, mLoginContentView.getText().toString());
  21.     }
  22.     @Override
  23.     public void tearDown() throws Exception {
  24.         super.tearDown();
  25.     }
  26. }

接下来是运行测试用例,首先我们需要把要测试的程序安装到模拟器或真机上

运行测试用例,查看运行结果

这里仅仅讲了使用eclipse来进行单元测试,当然也是可以在命令行中进行单元测试的,但既然有eclipse这种图形界面的工具,就不再折腾什么命令行了。
还有就是测试用例也可以直接创建在源程序中(即源代码和测试代码放在一个项目中),具体怎么做的话google一些吧,就是把测试时涉及的一些Manifest元素移到源码工程的Manifest中等

除非注明,文章均为( noway )原创,转载请保留链接: http://blog-old.z3a105.com/?p=118




       ==QQ:122320466==

 微信    QQ群


0

Aujourd’hui, une partie avec le développement du e-commerce, achats en ligne est devenu une partie de la vie pour beaucoup de gens. La mariage a commencé achats en ligne. Si vous choisissez achats les mariages en ligne, il peut être beaucoup moins cher que le salon de la Robe de mariée pas chermariée local, réduisant le budget de mariage. vous pouvez avoir beaucoup de choix si acheter de mariage en ligne. vous pouvez ramasser une robe de mariée bon marché sur Internet.
Piercing fascinerande figur, och nu tittar vi på 2016 senast brudklänning, kan du vara den vackraste bruden det!2016 senaste Bra brudklänning, söt temperament Bra design, romantiska spetsar blomma kjol, som du lägger till en elegant och charmig temperament.Kvinnan tillbaka mjuka linjer, människor brudklänningofta få en känsla av oändlig frestelse. Fall 2016 mässan, lämnar uppgifter om ditt bröllop charmig.
Yesterday afternoon, the Chinese team was training in the Guangzhou Gymnasium, when the reporter asked Zhao Yunlei the feeling of wearing the new cheap jersey , cheap jerseys online shopshe readily took a shirt from the bag crumpled ball to reporters, and she said with a smile: ” This shirt is light. ”Zhao Yunlei said: “Our material is very light like with the clothes of the tennis King Nadal, Federer, after the sweat, sweat does not drip down to the ground, when we do move, it is easy pace slipping if the sweat drip on the floor.”Tennis players Zhang Yawen, told reporters: “You might think the clothes attached to the body, fearing we swing will be affected, in fact, we do not feel anything, because the clothes are very light, very soft, put on quite comfortable. And it’s particularly good clothes to dry, washing and will dry in 15 minutes. ”
China’s sports enthusiasts NFL sweatshirt with mad love and the pursuit of, and therefore, NFL jerseys have a good market in China and development. China is a populous country, is the consumer, the economic momentum is so good, the sales prospects sportswear is immeasurable. With hot sales sweatshirt, but also to promote the importance of sports fans, on health, on the other hand is a matter of concern for the World Cup, fans wearing NFL jerseys and also can express themselves more fully love and obsession Therefore, NFL jerseys Wholesale jerseys online shopwholesale has good prospects and development in China.
ANTA-ANTA Sports Products Limited, referred to as ANTA Sports, Anta, is China’s leading sporting goods companies, mainly engaged in the design, development, manufacture and marketing of ANTA brand sporting goods, including sports footwear, apparel and accessories. Anta sweatshirt design advantages, warm stretch knit fabric, using Slim version of model, more personal fit, bid farewell to bloated, so wearing more stylish.GUIRENNIAO-This logo is a spiritual totem, smooth graphics implication unstoppable force; flexible deliver an elegant arc Wholesale jerseys china shop movement, strength and speed of the United States, a symbol of passion and rationality publicity “Heart” and “meaning”, “concept” unity; pass the fearless and enterprising mind, showing beyond the realm of self, to unstoppable force to create the future.XTEP-Xtep (China) Co., Ltd. is a comprehensive development wholesale jerseys china shop, production and marketing of Xtep brand (XTEP) sports shoes, clothing, bags, caps, balls, socks mainly large sporting goods industry enterprises.
There are a lot of fans in identifying the authenticity of the above cheap jerseys have great distress, so here to i will show you some methods to definitely affordable inexpensive cheap jerseys : Firstly, we should look at if it is working fine. China has been called the world’s factory, a lot cheap jerseys factories in China have foundries, but our cheap jerseys are all from here! Secondly, should to see whether it is the , we all know that it is difficult to get out of print once a genuine cheap cheap jerseys free shipping jersey was print. and we have all kind of stocka on the whole website, in other words, we have all you want ! Finally, look at the price, our price is not necessarily the lowest in the whole website but it must be most fair on the whole website, we certainly you will not regret later when you buy it. Of course, except that cheap jerseys, we also have the other products, such as socks, leggings and some other related products, everyone can enjoy the best services of here!

KUBET