android instrumentation 原理,理解 android instrumentation

instrumentation

先看activity的启动过程:

@Override

public void startActivity(Intent intent, @Nullable Bundle options) {

if (options != null) {

startActivityForResult(intent, -1, options);

} else {

// Note we want to go through this call for compatibility with

// applications that may have overridden the method.

startActivityForResult(intent, -1);

}

}

继续看startActivityForResult:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,

@Nullable Bundle options) {

if (mParent == null) {

Instrumentation.ActivityResult ar =

mInstrumentation.execStartActivity(

this, mMainThread.getApplicationThread(), mToken, this,

intent, requestCode, options);

if (ar != null) {

mMainThread.sendActivityResult(

mToken, mEmbeddedID, requestCode, ar.getResultCode(),

ar.getResultData());

}

if (requestCode >= 0) {

// If this start is requesting a result, we can avoid making

// the activity visible until the result is received. Setting

// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the

// activity hidden during this time, to avoid flickering.

// This can only be done when a result is requested because

// that guarantees we will get information back when the

// activity is finished, no matter what happens to it.

mStartedActivity = true;

}

cancelInputsAndStartExitTransition(options);

// TODO Consider clearing/flushing other event sources and events for child windows.

} else {

if (options != null) {

mParent.startActivityFromChild(this, intent, requestCode, options);

} else {

// Note we want to go through this method for compatibility with

// existing applications that may have overridden it.

mParent.startActivityFromChild(this, intent, requestCode);

}

}

}

这里我们看到activity的启动是由 instrumentation的execStartActivity执行的。

这种设计即委托观察者模式。

public ActivityResult execStartActivity(

Context who, IBinder contextThread, IBinder token, Activity target,

Intent intent, int requestCode, Bundle options) {

IApplicationThread whoThread = (IApplicationThread) contextThread;

Uri referrer = target != null ? target.onProvideReferrer() : null;

if (referrer != null) {

intent.putExtra(Intent.EXTRA_REFERRER, referrer);

}

if (mActivityMonitors != null) {

synchronized (mSync) {

final int N = mActivityMonitors.size();

for (int i=0; i

final ActivityMonitor am = mActivityMonitors.get(i);

if (am.match(who, null, intent)) {

am.mHits++;

if (am.isBlocking()) {

return requestCode >= 0 ? am.getResult() : null;

}

break;

}

}

}

}

try {

intent.migrateExtraStreamToClipData();

intent.prepareToLeaveProcess(who);

int result = ActivityManagerNative.getDefault()

.startActivity(whoThread, who.getBasePackageName(), intent,

intent.resolveTypeIfNeeded(who.getContentResolver()),

token, target != null ? target.mEmbeddedID : null,

requestCode, 0, null, options);

checkStartActivityResult(result, intent);

} catch (RemoteException e) {

throw new RuntimeException("Failure from system", e);

}

return null;

}

自动化测试,instrumentaiontestcase:

testactivity = (testClass)getInstrumentation().startActivitySync(intent);

text = testactivity.findViewById(R.id.text1);

assertEquals("hello,world", text.getText().toString());

...不知道源码也可以的。

/** This testcase starts the same activity and sending a key event to that activity under test*/

private void testcase3() {

Intent intent = new Intent(Intent.ACTION_MAIN);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.putExtra(“STRING”, “Hai”);

intent.setClassName(getTargetContext(), "MyActivity.class");

MyActivity activity = (MyActivity)startActivitySync(_intent);

act = new ActivityRunnable(activity);

runOnMainSync(act);

package com.mycompany;

import android.app.*;

import android.content.*;

import android.test.*;

import android.test.suitebuilder.annotation.*;

import android.util.*;

import android.view.*;

import android.widget.*;

import static org.hamcrest.core.Is.*;

import static org.hamcrest.core.IsNull.*;

import static org.hamcrest.core.IsInstanceOf.instanceOf;

import static org.junit.Assert.*;

import static com.mycompany.R.id.*;

public class LoginTests extends InstrumentationTestCase {

@MediumTest

public void testAValidUserCanLogIn() {

Instrumentation instrumentation = getInstrumentation();

// Register we are interested in the authentication activiry...

Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(AuthenticateActivity.class.getName(), null, false);

// Start the authentication activity as the first activity...

Intent intent = new Intent(Intent.ACTION_MAIN);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setClassName(instrumentation.getTargetContext(), AuthenticateActivity.class.getName());

instrumentation.startActivitySync(intent);

// Wait for it to start...

Activity currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);

assertThat(currentActivity, is(notNullValue()));

// Type into the username field...

View currentView = currentActivity.findViewById(username_field);

assertThat(currentView, is(notNullValue()));

assertThat(currentView, instanceOf(EditText.class));

TouchUtils.clickView(this, currentView);

instrumentation.sendStringSync("MyUsername");

// Type into the password field...

currentView = currentActivity.findViewById(password_field);

assertThat(currentView, is(notNullValue()));

assertThat(currentView, instanceOf(EditText.class));

TouchUtils.clickView(this, currentView);

instrumentation.sendStringSync("MyPassword");

// Register we are interested in the welcome activity...

// this has to be done before we do something that will send us to that

// activity...

instrumentation.removeMonitor(monitor);

monitor = instrumentation.addMonitor(WelcomeActivity.class.getName(), null, false);

// Click the login button...

currentView = currentActivity.findViewById(login_button;

assertThat(currentView, is(notNullValue()));

assertThat(currentView, instanceOf(Button.class));

TouchUtils.clickView(this, currentView);

// Wait for the welcome page to start...

currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);

assertThat(currentActivity, is(notNullValue()));

// Make sure we are logged in...

currentView = currentActivity.findViewById(welcome_message);

assertThat(currentView, is(notNullValue()));

assertThat(currentView, instanceOf(TextView.class));

assertThat(((TextView)currentView).getText().toString(), is("Welcome, MyUsername!"));

}

}

uiautomator

简单看一下uiautomator,首先,instrumentation 用来做UI测试受制于android的安全策略,本质上是一个APP测试,需要和被测APP在相同签名下,相同的进程下,才能互相信任,获取控件状态。因此,如果不知道源码,不要对APP重签名;另外,instrumentaion比较底层,封装程度不高,因此不适合直接拿来测试。从android API LEVEL 16开始,android引入了新的测试框架uiautomator,它对UI测试做了高度封装,同时不依赖于instrumentation,不需要做签名校验,可直接通过系统调用,获取被测应用控件。非常方便。以后详细介绍。

来自微信公众帐号:myersguo

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值