Andorid API TestDemo 解析

来源:互联网 发布:2003网络歌手名单大全 编辑:程序博客网 时间:2024/05/22 03:50

怎样导入测试工程

第1步 ,新建一个Android项目,选择“create project from existing source”,并把路径指向android-sdk-1.5/platforms/android-1.5/samples/ApiDemos


这一步导入错误一般情况为:sdk版本不对   换工程为4.2或者其他的工程版本。

有些同学像是缺少R文件啊  什么的 都是这一类的问题。
第2步 ,再新建一个Android项目,依然通过“create project from existing source”的方式,这次把路径指向android-sdk-1.5/platforms/android-1.5/samples/ApiDemos/tests
这时候ADT会报错,因为它无法找到APIDemo项目。右键,选择Properties,在Java Build Path –> Projects中添加APIDemo项目即可。
第3步 ,以“Android Application”方式运行第一个项目(注意正确设置AVD),APIDemo将被安装到模拟器。
第4步 ,以“Android Application”方式运行第二个项目(注意正确设置AVD),APIDemo Test将被安装到模拟器。
第5步 ,现在,我们可以通过Dev Tools中的Instrumentation来执行APIDemo Test了。找到Instrumentation中的”Tests for API Demos.”,点击即可开始测试。
Instrumentation
这时,通过LogCat即可看到测试结果。
Test result in LogCat

除了通过Dev Tools来执行单元测试,我们还有另外两种方法:
1、通过ADT,在eclipse中执行测试
在eclipse中选中test项目,直接Run As “Android JUnit Test”既可以,测试结果会以图形化的方式返回。
Test result in eclipse

2、通过sdb shell命令执行测试
在命令行中执行 adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner 命令
测试结果如下:
Test through ADB Shell
其中,com.example.android.apis.tests是APIDemo Test所在的package。

那么,我们如何创建自己的test项目呢?
大致的步骤如下:
1、新建一个普通的Android项目,比如项目名为Foo,Package为com.foo.bar
2、新建一个Test项目,注意把Package填成com.foo.bar.tests ,项目名任意,比如FooTest,Application name任意
3、在FooTest项目的Build Path中添加Foo项目
4、参照APIDemo Test项目的manifext.xml来修改FooTest项目的manifest.xml
5、编写TestCase

API TestDemo 解释

这里AllTests 是一个TestSuite, 包含了该类所在 包以及该包的子包下所有的测试用例。

* AllTests类

public class AllTests extends TestSuite {

public static Test suite() {

return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build();

}

}

includeAllPackagesUnderHere()

Include all junit tests that satisfy the requirements in the calling class' package and all sub-packages

build()

call this method once you have configured your builder as desired.

this method returns the suilte containing the requested tests.

如果是通过命令行的方式运行测试用例的话, 有如下几种命令:

1 运行该Apk文件下所有的测试套件

adb shell am instrument -w /

com.example.android.apis .tests/ android.test.InstrumentationTestRunner

2 运行单个的TestSuilte

adb shell am instument -w /

-e class com.example.android.apis.Alltests /

com.example.android.apis.tests/ android.test.InstrumentationTestRunner

3 运行单个TestSuilte下的单个TestCase:

adb shell am instrument -w

-e class com.example.android.apis.os.MorseCodeConverterTest /

com.example.android.apis/android.test.InstrumentationTestRunner

4 运行单个TestCase下的某个分支

adb shell am instrument -w /

-e class com.example.android.apis.os.MorseCodeConverterTest#testCharacters /

com.example.android.apis/android.test.InstrumentationTestRunner

* ApiDemoTest类

public class ApiDemosTest extends ActivityInstrumentationTestCase<ApiDemos> {

/**
* The first constructor parameter must refer to the package identifier of the
* package hosting the activity to be launched, which is specified in the AndroidManifest.xml
* file. This is not necessarily the same as the java package name of the class - in fact, in
* some cases it may not match at all.
*/
public ApiDemosTest() {
super("com.example.android.apis", ApiDemos.class);
}

如上,在测试的时候,我们可以验证“程序入口”Activity 是否正确加载。

上述super 方法中的第一参数是即将被启动的Activity所在的包名。这和AndroidManifest,xml

文件中定义的程序的package 属性指向的位置相同。

系统通过ActivityInstrumentationTestCase#testActivityTestCaseSetUpProperly()方法进行验证。

* ApiDemoApplicationTests类

这是一个测试Application的举例。

public class ApiDemosApplicationTests extends ApplicationTestCase<ApiDemosApplication> {

public ApiDemosApplicationTests ( ) {

super(ApiDemosApplication.class);

}

protected void setUp ( ) throws Exception {

super.setUp();

}


/**
* The name 'test preconditions' is a convention to signal that if this
* test doesn't pass, the test case was not set up properly and it might
* explain any and all failures in other tests. This is not guaranteed
* to run before other tests, as junit uses reflection to find the tests.
*/

如果这个测试用例中的断言语句不通过 的话,这就说明setUp( )方法中初始化存在问题。

下面的单元测试也就没有什么意义了。

public void testPreconditions ( ) {

}

/**
* Test basic startup/shutdown of Application
*/

public void testSimpleCreate ( ) {

createApplication ( );

}

}

createAplication():

Start the Application under test, in the same way as if it was started by the system.

If you use this method to start the Application, it will automatically be stopped by

tearDown(). If you wish to inject a specialized Context for your test,by calling

setContext(), you must do so before calling this method.
通过该方法启动应用程序,和通过系统启动该程序是一样 的。 如果通过该方法启动

应用程序,当执行tearDown( )方法的时候,该应用会自动停止。

ApplicationTestCase --- 测试整个应用程序的类。它允许你注入一个模拟的Context到应

用程序中,在应用程序启动之前初始化测试参数,并在应用程序结束之后贤惠之前检查的应用。

This test case provides a framework in which you can test Application classes in a controlled

environment. It provides basic support for the lifecycle of a Application, and hooks by which

you can inject various dependencies and control the environment in which your Application is tested.

* Focus2ActivityTest类

/**
* An example of an {@link ActivityInstrumentationTestCase} of a specific activity {@link Focus2}.
* By virtue of extending {@link ActivityInstrumentationTestCase}, the target activity is automatically
* launched and finished before and after each test. This also extends
* {@link android.test.InstrumentationTestCase}, which provides
* access to methods for sending events to the target activity, such as key and
* touch events. See {@link #sendKeys}.
*
* In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase}s
* are heavier weight functional tests available for end to end testing of your
* user interface. When run via a {@link android.test.InstrumentationTestRunner},
* the necessary {@link android.app.Instrumentation} will be injected for you to
* user via {@link #getInstrumentation} in your tests.
*
* See {@link com.example.android.apis.app.ForwardingTest} for an example of an Activity unit test.
*
* See {@link com.example.android.apis.AllTests} for documentation on running
* all tests and individual tests in this application.
*/

该测试类通过继承ActivityInstrumentationTestCase, 被测试的Activity会自动的启动和关闭在执行具体的测试

分支之前。 该类还提供了发送事件给目标Activity的方法。 例如Key 和 touch 事件。

public class Focus2ActivityTest extends ActivityInstrumentationTestCase<Focus2> {

private Button mLeftButton;
private Button mCenterButton;
private Button mRightButton;

/**
* The first constructor parameter must refer to the package identifier of the
* package hosting the activity to be launched, which is specified in the AndroidManifest.xml
* file. This is not necessarily the same as the java package name of the class - in fact, in
* some cases it may not match at all.
*/


public Focus2ActivityTest() {
super("com.example.android.apis", Focus2.class);
}

@Override
protected void setUp() throws Exception {
super.setUp();
final Focus2 a = getActivity();
mLeftButton = (Button) a.findViewById(R.id.leftButton);
mCenterButton = (Button) a.findViewById(R.id.centerButton);
mRightButton = (Button) a.findViewById(R.id.rightButton);
}

/**
* The name 'test preconditions' is a convention to signal that if this
* test doesn't pass, the test case was not set up properly and it might
* explain any and all failures in other tests. This is not guaranteed
* to run before other tests, as junit uses reflection to find the tests.
*/
@MediumTest
public void testPreconditions() {
assertTrue("center button should be right of left button",
mLeftButton.getRight() < mCenterButton.getLeft());
assertTrue("right button should be right of center button",
mCenterButton.getRight() < mRightButton.getLeft());
assertTrue("left button should be focused", mLeftButton.isFocused());
}

@MediumTest
public void testGoingRightFromLeftButtonJumpsOverCenterToRight() {
sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
assertTrue("right button should be focused", mRightButton.isFocused());
}

@MediumTest
public void testGoingLeftFromRightButtonGoesToCenter() {
// Give right button focus by having it request focus. We post it
// to the UI thread because we are not running on the same thread, and
// any direct api calls that change state must be made from the UI thread.
// This is in contrast to instrumentation calls that send events that are
// processed through the framework and eventually find their way to
// affecting the ui thread。

getActivity().runOnUiThread(new Runnable() {
public void run() {
mRightButton.requestFocus();
}
});
// wait for the request to go through
getInstrumentation().waitForIdleSync();

assertTrue(mRightButton.isFocused());

sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
assertTrue("center button should be focused", mCenterButton.isFocused());
}
}

ActivityInstrumentationTeseCase2---在正常的系统环境中测试单个Activiry的类。、

你不能注入一个模拟的Context, 但是你可以注入一个模拟的Intent,另外你还可以在

UI线程(应用程序的主线程)运行测试方法,并且可以给应用程序UI发送按键和触摸事件。

* Focus2AndroidTest类

package com.example.android.apis.view;

import com.example.android.apis.R;

import android.content.Context;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.FocusFinder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

/**
* This exercises the same logic as {@link Focus2ActivityTest} but in a lighter
* weight manner; it doesn't need to launch the activity, and it can test the
* focus behavior by calling {@link FocusFinder} methods directly.
*
* {@link Focus2ActivityTest} is still useful to verify that, at an end to end
* level, key events actually translate to focus transitioning in the way we expect.
* A good complementary way to use both types of tests might be to have more exhaustive
* coverage in the lighter weight test case, and a few end to end scenarios in the
* functional {@link android.test.ActivityInstrumentationTestCase}. This would provide reasonable
* assurance that the end to end system is working, while avoiding the overhead of
* having every corner case exercised in the slower, heavier weight way.
*
* Even as a lighter weight test, this test still needs access to a {@link Context}
* to inflate the file, which is why it extends {@link AndroidTestCase}.
*
* If you ever need a context to do your work in tests, you can extend
* {@link AndroidTestCase}, and when run via an {@link android.test.InstrumentationTestRunner},
* the context will be injected for you.
*
* See {@link com.example.android.apis.app.ForwardingTest} for an example of an Activity unit test.
*
* See {@link com.example.android.apis.AllTests} for documentation on running
* all tests and individual tests in this application.
*/

该类继承了AndroidTestCase, 这个测试类和上面测试的是同一个类。只是继承了AndroidTestCase ,

更加轻量些。通过这个类,我们不需要启动Activity,就可以测试焦点获得是否成功通过 FocusFinder。

虽然是一个轻量级的类,但是该类仍然需要得到一个Contex用来获取 inflater.

如果在你的测试用例中需要Context, 你可以使用AndroidTestCase. and when run via an{@ link android.test

InstrumentationTestRunner}, 系统为自动为你注入这个Context.

public class Focus2AndroidTest extends AndroidTestCase {

private FocusFinder mFocusFinder;

private ViewGroup mRoot;

private Button mLeftButton;
private Button mCenterButton;
private Button mRightButton;

@Override
protected void setUp() throws Exception {
super.setUp();

mFocusFinder = FocusFinder.getInstance();

// inflate the layout
final Context context = getContext();
final LayoutInflater inflater = LayoutInflater.from(context);
mRoot = (ViewGroup) inflater.inflate(R.layout.focus_2, null);

// manually measure it, and lay it out
mRoot.measure(500, 500);
mRoot.layout(0, 0, 500, 500);

mLeftButton = (Button) mRoot.findViewById(R.id.leftButton);
mCenterButton = (Button) mRoot.findViewById(R.id.centerButton);
mRightButton = (Button) mRoot.findViewById(R.id.rightButton);
}

/**
* The name 'test preconditions' is a convention to signal that if this
* test doesn't pass, the test case was not set up properly and it might
* explain any and all failures in other tests. This is not guaranteed
* to run before other tests, as junit uses reflection to find the tests.
*/
@SmallTest
public void testPreconditions() {
assertNotNull(mLeftButton);
assertTrue("center button should be right of left button",
mLeftButton.getRight() < mCenterButton.getLeft());
assertTrue("right button should be right of center button",
mCenterButton.getRight() < mRightButton.getLeft());
}

@SmallTest
public void testGoingRightFromLeftButtonJumpsOverCenterToRight() {
assertEquals("right should be next focus from left",
mRightButton,
mFocusFinder.findNextFocus(mRoot, mLeftButton, View.FOCUS_RIGHT));
}

@SmallTest
public void testGoingLeftFromRightButtonGoesToCenter() {
assertEquals("center should be next focus from right",
mCenterButton,
mFocusFinder.findNextFocus(mRoot, mRightButton, View.FOCUS_LEFT));
}
}

* ForwardingTest类

/**
* This demonstrates completely isolated "unit test" of an Activity class.
*
* <p>This model for testing creates the entire Activity (like {@link Focus2ActivityTest}) but does
* not attach it to the system (for example, it cannot launch another Activity). It allows you to
* inject additional behaviors via the
* {@link android.test.ActivityUnitTestCase#setActivityContext(Context)} and
* {@link android.test.ActivityUnitTestCase#setApplication(android.app.Application)} methods.
* It also allows you to more carefully test your Activity's performance
* Writing unit tests in this manner requires more care and attention, but allows you to test
* very specific behaviors, and can also be an easier way to test error conditions.
*
* <p>Because ActivityUnitTestCase creates the Activity under test completely outside of
* the usual system, tests of layout and point-click UI interaction are much less useful
* in this configuration. It's more useful here to concentrate on tests that involve the
* underlying data model, internal business logic, or exercising your Activity's life cycle.
*
* <p>See {@link com.example.android.apis.AllTests} for documentation on running
* all tests and individual tests in this application.
*/

这个测试模型虽然生成了被测试的activity, 但是独立于系统。例如, 它不能启动其他的

Activity, 该类通过相应的方法注入其他的组件,setActivityContext(Context), setApplication(

android.app.Application). 我们可以通过该测试模型更加关注Activity 的性能。测试错误的分支等。

因为这个测试模型生成的Activity 是独立于系统的,所以测试 画面布局和UI交互的用例一般不继承该类。

该类对于测试底层的数据模型,内部的业务逻辑,Activity 的声明周期是可行的。

public class ForwardingTest extends ActivityUnitTestCase<Forwarding> {

private Intent mStartIntent;
private Button mButton;

public ForwardingTest() {
super(Forwarding.class);
}

@Override
protected void setUp() throws Exception {
super.setUp();

// In setUp, you can create any shared test data, or set up mock components to inject
// into your Activity. But do not call startActivity() until the actual test methods.
mStartIntent = new Intent(Intent.ACTION_MAIN);
}

/**
* The name 'test preconditions' is a convention to signal that if this
* test doesn't pass, the test case was not set up properly and it might
* explain any and all failures in other tests. This is not guaranteed
* to run before other tests, as junit uses reflection to find the tests.
*/
@MediumTest
public void testPreconditions() {
startActivity(mStartIntent, null, null);
mButton = (Button) getActivity().findViewById(R.id.go);

assertNotNull(getActivity());
assertNotNull(mButton);
}

/**
* This test demonstrates examining the way that activity calls startActivity() to launch
* other activities.
*/
@MediumTest
public void testSubLaunch() {
Forwarding activity = startActivity(mStartIntent, null, null); 启动的是被测试的Activity.
mButton = (Button) activity.findViewById(R.id.go);

// This test confirms that when you click the button, the activity attempts to open
// another activity (by calling startActivity) and close itself (by calling finish()).
mButton.performClick();

assertNotNull(getStartedActivityIntent());
assertTrue(isFinishCalled());
}

/**
* This test demonstrates ways to exercise the Activity's life cycle.
*/
@MediumTest
public void testLifeCycleCreate() {
Forwarding activity = startActivity(mStartIntent, null, null);

// At this point, onCreate() has been called, but nothing else
// Complete the startup of the activity
getInstrumentation().callActivityOnStart(activity);
getInstrumentation().callActivityOnResume(activity);

// At this point you could test for various configuration aspects, or you could
// use a Mock Context to confirm that your activity has made certain calls to the system
// and set itself up properly.

getInstrumentation().callActivityOnPause(activity);

// At this point you could confirm that the activity has paused properly, as if it is
// no longer the topmost activity on screen.

getInstrumentation().callActivityOnStop(activity);

// At this point, you could confirm that the activity has shut itself down appropriately,
// or you could use a Mock Context to confirm that your activity has released any system
// resources it should no longer be holding.

// ActivityUnitTestCase.tearDown(), which is always automatically called, will take care
// of calling onDestroy().
}

}

ActivityUnitTestCase——对单个Activity进行单一测试的类。使用它,你可以注入模拟的Context或 Application,或者两者。它用于对Activity进行单元测试。不同于其它的Instrumentation类,这个测试类不能注入模拟的 Intent。

原创粉丝点击