Android test framework

转载请注明来自:http://blog.csdn.net/liaoqianchuan00/article/details/23032357

1.  基本

1.  常用Assertions

l   assertEquals

l   assertFalse?

l   assertNotNull

l   assertNotSame

l   assertNull

l   assertSame

l   assertTrue

l   fail

2.  自定义输出语句

public void testMax() {

final int a = 1;

final int b = 2;

final int expected = b;

final int actual = Math.max(a, b);

assertEquals("Expection " + expected + " but was " + actual, expected,   actual);

}

3.   控件Assertions

l   assertBaselineAligned: Asserts that two views arealigned on their baseline, that is their baselines are on the same y location.

l   assertBottomAligned: Asserts that two views arebottom aligned, that is their bottom edges are on the same y location.

l   assertGroupContains: Asserts that the specifiedgroup contains a specific child once and only once.

l   assertGroupIntegrity: Asserts the specified group'sintegrity. The children count should be >= 0 and each child should benon-null.

l   assertGroupNotContains: Asserts that the specifiedgroup does not contain a specific child.

l   assertHasScreenCoordinates: Asserts that a view hasa particular x and y position on the visible screen.

l   assertHorizontalCenterAligned: Asserts that the testview is horizontally center aligned with respect to the reference view.

l   assertLeftAligned: Asserts that two views are leftaligned, that is their left edges are on the same x location. An optionalmargin can also be provided.

l   assertOffScreenAbove: Asserts that the specifiedview is above the visible screen.

l   assertOffScreenBelow: Asserts that the specifiedview is below the visible screen.

l   assertOnScreen: Asserts that a view is on thescreen.

l   assertRightAligned: Asserts that two views areright-aligned, that is their right edges are on the same x location. Anoptional margin can also be specified.

l   assertTopAligned: Asserts that two views aretop-aligned, that is their top edges are on the same y location. An optionalmargin can also be specified.

l   assertVerticalCenterAligned: Asserts that the testview is vertically center aligned with respect to the reference view.

4.  TouchUtils

l   Clicking on a View and releasing it

l   Tapping on a View, that is touching it and quicklyreleasing

l   Long clicking on a View

l   Dragging the screen

public void testListScrolling() {

mListView.scrollTo(0, 0);

TouchUtils.dragQuarterScreenUp(this, mActivity);

TouchUtils.dragQuarterScreenUp(this, mActivity);

TouchUtils.dragQuarterScreenUp(this, mActivity);

TouchUtils.dragQuarterScreenUp(this, mActivity);

TouchUtils.tapView(this, mListView);

final int expectedItemPosition = 6;

final int actualItemPosition =

mListView.getFirstVisiblePosition();

assertEquals("Wrong position",

expectedItemPosition, actualItemPosition);

final String expected = "Anguilla";

final String actual = mListView.getAdapter().

getItem(expectedItemPosition).toString();

assertEquals("Wrong content", actual, expected);

}

5.  Mock对象

l   MockApplication: A mock implementation of the Application class. All methods arenon-functional and throw UnsupportedOperationException.

l   MockContentProvider: A mock implementation of ContentProvider. All methods arenon-functional and throw UnsupportedOperationException.

l   MockContentResolver: A mock implementation of the ContentResolver class that isolatesthe test code from the real content system. All methods are non-functional andthrow UnsupportedOperationException.

l   MockContext: A mock Context class. This can be used to inject otherdependencies. All methods are non-functional and throwUnsupportedOperationException.

l   MockCursor: A mock Cursor class that isolates the test code from real Cursorimplementation. All methods are non-functional and throwUnsupportedOperationException.

l   MockDialogInterface: A mock implementation of DialogInterface class. All methods arenon-functional and throw UnsupportedOperationException.

l   MockPackageManager: A mock implementation of PackageManager class. All methods arenon-functional and throw UnsupportedOperationException.

l   MockResources: A mock Resources class. All methods are non-functional and throw UnsupportedOperationException.

2.  框架结构

1     AndroidTestCase

当你需要用到Activity Context的时候就使用这个类,比如Resources,database,file system,你可以是用mContext来是用context。你可以用ontext.startActivity()来启动多个Activity。

有很多个testcase继承自这个类:

l   ApplicationTestCase

l   ProviderTestCase2

l  ServiceTestCase

2     Instrumentation

这个是用来监视Activity和Application的,你可以用它来控制Activity的生命周期和用户交互事件。

l   我们可以是用Instrumentation.ActivityMonitor来监测一个Activity。例如:

public void testFollowLink() {

final Instrumentation inst = getInstrumentation();

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);

intentFilter.addDataScheme("http");

intentFilter.addCategory(Intent.CATEGORY_BROWSABLE);

ActivityMonitor monitor = inst.addMonitor(

IntentFilter, null, false);

assertEquals(0, monitor.getHits());

TouchUtils.clickView(this, mLink);              monitor.waitForActivityWithTimeout(5000);

assertEquals(1, monitor.getHits()); inst.removeMonitor(monitor);

}

l   使用Instrumentation来测试activities,它的生命周期的函数不会自动调用,只有onCreate方法会自动调用,你可以调用其他的生命周期通过getInstrumentation().callActivityOnXXX。

3     InstrumentationTestCase

它的子类:

l   ActivityTestCase

l   ProviderTestCase2

l   SingleLaunchActivityTestCase

l   SyncBaseInstrumentation

l   ActivityInstrumentationTestCase2

l   ActivityUnitTestCase

注意:android.test.ActivityInstrumentationTestCase从Android1.5开始已经不建议使用了,可以是用android.test.ActivityInstrumentationTestCase2替代。

3.  例子程序

1.  被测试程序

package com.vogella.android.test.simpleactivity;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.view.View;

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

public void onClick(View view) {

Intent intent = new Intent(this, SecondActivity.class);

intent.putExtra("URL", "http://www.vogella.com");

startActivity(intent);

}

}

2.  单元测试

package com.vogella.android.test.simpleactivity.test;

import android.content.Intent;

import android.test.TouchUtils;

import android.test.suitebuilder.annotation.SmallTest;

import android.widget.Button;

import com.vogella.android.test.simpleactivity.MainActivity;

public class MainActivityUnitTest extends

android.test.ActivityUnitTestCase {

private int buttonId;

private MainActivity activity;

public MainActivityUnitTest() {

super(MainActivity.class);

}

@Override

protected void setUp() throws Exception {

super.setUp();

Intent intent = new Intent(getInstrumentation().getTargetContext(),

MainActivity.class);

startActivity(intent, null, null);

activity = getActivity();

}

public void testLayout() {

buttonId = com.vogella.android.test.simpleactivity.R.id.button1;

assertNotNull(activity.findViewById(buttonId));

Button view = (Button) activity.findViewById(buttonId);

assertEquals("Incorrect label of the button", "Start", view.getText());

}

public void testIntentTriggerViaOnClick() {

buttonId = com.vogella.android.test.simpleactivity.R.id.button1;

Button view = (Button) activity.findViewById(buttonId);

assertNotNull("Button not allowed to be null", view);

view.performClick();

// TouchUtils cannot be used, only allowed in

// InstrumentationTestCase or ActivityInstrumentationTestCase2

// Check the intent which was started

Intent triggeredIntent = getStartedActivityIntent();

assertNotNull("Intent was null", triggeredIntent);

String data = triggeredIntent.getExtras().getString("URL");

assertEquals("Incorrect data passed via the intent",

"http://www.vogella.com", data);

}

}

3.  功能测试

package com.vogella.android.test.simpleactivity.test;

import android.app.Activity;

import android.app.Instrumentation;

import android.app.Instrumentation.ActivityMonitor;

import android.test.ActivityInstrumentationTestCase2;

import android.test.TouchUtils;

import android.test.ViewAsserts;

import android.view.KeyEvent;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

import com.vogella.android.test.simpleactivity.R;

import com.vogella.android.test.simpleactivity.MainActivity;

import com.vogella.android.test.simpleactivity.SecondActivity;

public class MainActivityFunctionalTest extends

ActivityInstrumentationTestCase2 {

private MainActivity activity;

public MainActivityFunctionalTest() {

super(MainActivity.class);

}

@Override

protected void setUp() throws Exception {

super.setUp();

setActivityInitialTouchMode(false);

activity = getActivity();

}

public void testStartSecondActivity() throws Exception {

// add monitor to check for the second activity

ActivityMonitor monitor =

getInstrumentation().

addMonitor(SecondActivity.class.getName(), null, false);

// find button and click it

Button view = (Button) activity.findViewById(R.id.button1);

// TouchUtils handles the sync with the main thread internally

TouchUtils.clickView(this, view);

// to click on a click, e.g., in a listview

// listView.getChildAt(0);

// wait 2 seconds for the start of the activity

SecondActivity startedActivity = (SecondActivity) monitor

.waitForActivityWithTimeout(2000);

assertNotNull(startedActivity);

// search for the textView

TextView textView = (TextView) startedActivity.findViewById(R.id.resultText);

// check that the TextView is on the screen

ViewAsserts.assertOnScreen(startedActivity.getWindow().getDecorView(),

textView);

// validate the text on the TextView

assertEquals("Text incorrect", "Started", textView.getText().toString());

// press back and click again

this.sendKeys(KeyEvent.KEYCODE_BACK);

TouchUtils.clickView(this, view);

}

}

Robotium

public void testDisplayWhiteBox() {

//Defining our own values to multiply

float vFirstNumber = 10;

float vSecondNumber = 20;

float vResutl = vFirstNumber * vSecondNumber ;

//Access First value (edit-filed) and putting firstNumber value in it

EditText vFirstEditText = (EditText) solo.getView(R.id.EditText01);

solo.clearEditText(vFirstEditText);

solo.enterText(vFirstEditText, String.valueOf(vFirstNumber));

//Access Second value (edit-filed) and putting SecondNumber value in it

EditText vSecondEditText = (EditText) solo.getView(R.id.EditText02);

solo.clearEditText(vSecondEditText);

solo.enterText(vSecondEditText, String.valueOf(vSecondNumber));

//Click on Multiply button

solo.clickOnButton("Multiply");

assertTrue(solo.searchText(String.valueOf(vResutl)));

TextView outputField = (TextView) solo.getView(R.id.TextView01);

//Assert to verify result with visible value

assertEquals(String.valueOf(vResutl), outputField.getText().toString());

}

参考地址:

1     简介

Robotium是一款国外的Android自动化测试框架,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测试。另外,Robotium 4.0版本已经支持对WebView的操作。Robotium 对Activity,Dialog,Toast,Menu 都是支持的。

类似于selenium。

2     API

Solo类中提供了自动点击、取得、拖拽、搜索等各种方法。 声明Solo类型的成员变量privateSolo solo;

Activity&Fragment

assertCurrentActivity(text,Activity.class)- Ensure that the current activity equals the second parameter.

getCurrentActivity() .getFragmentManager().findFragmentById()-S earches for a fragment.

waitForActivity(SecondActivity.class,2000)- Waits for the specified activity for 2 seconds

点击

clickOnButton(int)—Clickson a Button with a given index.

clickOnButton(String)—Clickson a Button with a given text. clickOnCheckBox(int)—Clicks on a CheckBox with agiven index.  clickOnView(View)—Clicks ona given View.

clickOnText(String)—Clickson a View displaying a given text. clickLongOnText(String)—Long clicks on agiven View. clickOnRadioButton(int)—Clicks on a RadioButton with a given index.clickOnScreen(float, float)—Clicks on a given coordinate on the

screen.

clickInList(x);-Click on item number x in a ListView

clickOnSearch-Allows to click on part of the screen.

pressSpinnerItem(0,2);-Presses an item in a Spinner

sendKey(Solo.MENU);-Sends the menu key event.

goBack()-Pressthe back button

取得

getCurrentActivity()—Returnsthe current Activity.

GetText(String)—Returnsa TextView which shows a given text.

getView(int)—Returnsa View with a given id.

getEditText(String)—Returnsan EditText which shows a given text.  getImage(int)—Returns an ImageView with a given index.

拖拽

drag(float,float, float, float, int)—Simulate touching a given location and dragging it toa new location.

搜索

searchText(String)—Searchesfor a text string and returns true if at least one item is found with theexpected text.

searchEditText(String)—Searchesfor a text string in the EditText objects located in the current Activity.   S

earchButton(String,boolean)—Searches for a Button with the given text string and returns true ifat least one Button is found.

waitForText(text)

输入

enterText()-Entersa text.

界面判断

isCheckBoxChecked()-Checksif the checkbox is checked.

截屏

takeScreenshot()-Savesa screenshot on the device inthe /sdcard/Robotium-Screenshots/ folder. Requiresthe android.permission.WRITE_EXTERNAL_STORAGE permission in theAndroidManifest.xml ofthe application under test.

4.  QA

1.    在不知道ID的情况下怎么获取特定的view?

答:例如,ArrayList aa = solo.getCurrentViews(TextView.class), 然后断点调试查看是哪个view,TextViewtextview = aa.get(5);

2.    如何滚动和拖动?

答:solo.scrollXXX();solo.drag(初始X坐标,目标X坐标,Y,toY,步数); X,Y坐标可以通过HierarchyViewer工具获得,也可以通过Year.getLocationOnScreen(zuobiao)。

3.    Robotium和robolectric区别?

答:Robotium是通过ui线程进行测试,一般用于对应传统的集成或系统测试;

Robolectric 是单元测试框架,好处是第一运行在JVM上,速度、性能高;

解决了Android自身因为环境问题的缺点以及减少了许多用Mock的地方。

4. 如何识别webview对象?

答:可以根据XPATH来进行点击和输入

solo.clickOnWebElement(By.xpath(text));

solo.enterTextInWebElement(By.xpath(text),s);

或者根据ID来获取

solo.clickOnWebElement(By.id(text));

solo.enterTextInWebElement(By.id(text), s);

Mockito

1.  简介

流行的mock框架

# jMock

http://jmock.org/

# EasyMock

http://easymock.org/

# Mockito

使用Mockito不能用在下面的情况:

final classes

anonymous classes

primitive types

2.  使用方法

when(....).thenReturn(....)

或者

doReturn(object).when(kdskfsk).methodCall

使用verify来保证方法被调用到了

例如:

@Test

public void test1()  {

MyClass test = Mockito.mock(MyClass.class);

// define return value for method getUniqueId()

test.when(test.getUniqueId()).thenReturn(43);

// TODO use mock in test....

// now check if method testing was called with the parameter 12

Mockito.verify(test).testing(Matchers.eq(12));

// was the method called twice?

Mockito.verify(test, Mockito.times(2));

}

3.  Mock和Spy的区别

如果你mock了一个类,那么这个类的所有的函数都被Mockito改写了(如果是没有返回值的函数,则什么都不作,如果是有返回值,会返回默认值,比如布尔型的话返回false,List的话会返回一个空的列表,int的话会返回0等等),如果你Spy了一个类,那么所有的函数都没有被改变,除了那些被你打过桩的函数。看例子:

public class TestServiceImpl

{

public int getOrderCounts()

{

return 10;

}

}

@Test

public void MockVsSpy()

{

TestServiceImpl service = mock(TestServiceImpl.class);

//输出0,因为该函数被Mockito改写了

System.out.println("Order counts of mock object" + service.getOrderCounts());

when(service.getOrderCounts()).thenReturn(2);

//输出2, 因为我们给这个函数打了桩

System.out.println("Order counts of mock object AFTER stubs " + service.getOrderCounts());

service = new TestServiceImpl();

service = spy(service);

//输出10, 因为Mockito spy 不会改写已有的函数

System.out.println("Order counts of spy object" + service.getOrderCounts());

when(service.getOrderCounts()).thenReturn(2);

//输出2, 因为我们给这个函数打了桩

System.out.println("Order counts of spy object AFTER stubs " + service.getOrderCounts());

}

4.    如何写自定义的参数匹配器

看例子

public class Account

{

private String    name;

private String    adddress;

public Account(String name, String address)

{

this.name = name;

this.adddress = address;

}

...get/set 函数

}

public interface AccountDao

{

public void addAccount(Account a);

}

public class AccountServiceImpl

{

AccountDao dao;

public AccountServiceImpl(AccountDao dao)

{

this.dao = dao;

}

public void addAccount(String name, String address)

{

dao.addAccount(new Account(name, address));

}

}

public class AccountServiceImplTest

{

@Test

public void addAccount()

{

AccountDao dao = mock(AccountDao.class);

AccountServiceImpl service = new AccountServiceImpl(dao);

service.addAccount("obama", "white house");

verify(dao).addAccount(new Account("obama", "white house"));

}

}

上面的例子会失败,因为Mockito在做参数匹配时是根据equals函数的结果来判断两个参数是不是一样的。而我们的Account类并没有对equals作特殊的实现,所以会失败。修正的方法有三个,一个是改写Account类的equals函数。一个是用Mockito的反射相等匹配,就是把最后一句改成。

verify(dao).addAccount(refEq(new Account("obama", "white house")));

最后一种方法是写一个自定义的参数匹配器,如果Account的代码不是你控制的,那么你就只能选这种方法了。这时候最后一句要改成这样:

verify(dao).addAccount(argThat(new ArgumentMatcher()

{

@Override

public boolean matches(Object argument)

{

Account person = (Account)argument;

return person.getName().equals("obama") && person.getAddress().equals("white house") ? true : false;

}

}));

在Android中使用Mockito:

需要下载下面3个库文件。

http://dexmaker.googlecode.com/files/dexmaker-1.0.jar

http://dexmaker.googlecode.com/files/dexmaker-mockito-1.0.jar

https://code.google.com/p/mockito/

android mock测试资源,Android测试基础整理篇相关推荐

  1. android mock测试资源,Android测试教程 Mock之mockito,异步测试

    1. mockito是干什么的? Mock框架之一,其余的还有EasyMock,PowerMock等. Mock说白了就是打桩(Stub)或则模拟,当你调用一个不好在测试中创建的对象时,  Mock框 ...

  2. android mock测试资源,Android 单元测试 --Mock 及 Mockito

    以前我在 Mock 概念 所谓的 Mock 就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,主要提供两大功能: 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等 指定这个 ...

  3. 测试岗位面试前复习之【测试基础知识篇】

    测试基础知识篇 一.app测试相关 1.android与ios的app测试的区别: 2.app测试和web测试的重点: 3.性能测试考量的指标: 4.app的性能测试,需要重点关注哪些方面? 5.站在 ...

  4. Android 应用层组件安全测试基础实战技巧

    文章目录 前言 Adb Shell am指令 pm指令 other- Intent 组件间调用 setPackage 隐式意图劫持 拒绝服务攻击 DeepLink链接 组件权限 自定义权限 未定义权限 ...

  5. Android自定义控件开发系列(零)——基础原理篇

    在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇"基础原理篇",直接进入正题吧-- 首先的问题是:在Android项目开发中,什么时候 ...

  6. 重学Android基础系列篇(五):Android虚拟机指令

    前言 本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~ [非商业用途,如有侵权,请告 ...

  7. 日历 android 周历,Android Studio 基础 之 获取系统Calendar 日历日程 (涉及指定日期时间判断是星期几的方法使用)的方法整理...

    Android Studio 基础 之 获取系统Calendar 日历日程 (涉及指定日期时间判断是星期几的方法使用)的方法整理 目录 Android Studio 基础 之 获取系统Calendar ...

  8. Android测试(二):Android测试基础

    原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...

  9. Android自动化测试第一季(基础篇)-金阳光-专题视频课程

    Android自动化测试第一季(基础篇)-32195人已学习 课程介绍         Android自动化测试第一季 初级 课程收益     零基础 讲师介绍     金阳光 更多讲师课程      ...

最新文章

  1. 【青少年编程】【三级】躲避恐龙
  2. python求向量函数的雅可比矩阵_在python Numpy中求向量和矩阵的范数实例
  3. 电路与电子学-第一章直流电路分析方法小概括
  4. 利用QCustomePlot绘制热力图,瀑布图,频谱色图等
  5. ubuntu下修改文件夹权限
  6. 全国计算机二级准考证贵州,贵州计算机二级考试准考证打印时间
  7. com.mysql.jdbc.NotUpdatable: Result Set not updatable (references no primary keys).(解决方法)
  8. java 图片组合 分解_切分和组合图片(二)
  9. 微软:求你们别再用 IE 浏览器了
  10. 多输出模型的评价和模型预测
  11. ES组件elasticsearch-head报错 npm ERR! Please include the following file with any support request
  12. 关于linux下fork()函数的解析:子进程继续创建子进程,如何停止?
  13. URL和URI(二)URI
  14. 推荐个汇编语言编译器 XP系统
  15. 对于can通信过滤器的理解
  16. 手机html设计规范,手机网页设计尺寸规范具体是多少?
  17. 以自动化为“遮羞布”,亚马逊掩盖了惊人的工伤记录
  18. 创业6年,估值$750亿!张一鸣:人才不是核心竞争力,机制才是!
  19. python注册用户名和密码登录_用户名和密码登录
  20. 漫画算法python篇_漫画算法:小灰的算法之旅(Python篇)(全彩)

热门文章

  1. 投机者怎样于2019年3月18日前后的证券市场中利用底部放量实现程序化交易
  2. python读xml文件生成.h头文件_PYTHON读写xml文件的方法
  3. 2018蓝桥杯复现4
  4. socket 发送 TCP和UDP方式
  5. 计算机除尘的操作步骤,PC除尘降温不求人 脚本之家手把手教你如何清理电脑
  6. “我,35岁研发经理,月薪5W+,每年涨薪6-8K,特别焦虑” 评论区网友吵翻了
  7. 【高等数学笔记】彻底弄懂最小二乘法(Least Squares Method)
  8. iOS12 Siri ShortCuts 应用 (二)
  9. 【最小生成树】洛谷P2259 Charmer--viv
  10. 支付宝七(商户会员卡之发放卡券)