简体   繁体   中英

Use @Test annotation and ActivityTestRule with Robotium (Espresso-way)

I wonder how can i mark my test as @Test like in JUnit, because so far I have to use 'test...' name. It means:

@Test
private void creatingAcc(){

instead of

private void testCreatingAcc(){

Thanks in advance

Yes, you can do it. Follow these steps to achieve it:

  1. Go to your's app build.gradle file and add test dependendencies like below:

      androidTestCompile 'com.android.support.test:runner:0.4.1' androidTestCompile 'com.android.support.test:rules:0.4.1' androidTestCompile 'com.android.support:support-annotations:24.1.1' compile 'com.jayway.android.robotium:robotium-solo:5.6.1' 

    Now your build.gradle should look like:

     apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.1" defaultConfig { applicationId "com.example.piotr.myapplication" minSdkVersion 15 targetSdkVersion 21 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.1.1' compile 'com.android.support:design:24.1.1' androidTestCompile 'com.android.support.test:runner:0.4.1' androidTestCompile 'com.android.support.test:rules:0.4.1' androidTestCompile 'com.android.support:support-annotations:24.1.1' compile 'com.jayway.android.robotium:robotium-solo:5.6.1' } 
  2. Then you need to go to your androidTest directory and create Java class and name it for example MyActivityTestRule

  3. In this file put code below:

     @Beta public class MyActivityTestRule<T extends Activity> extends UiThreadTestRule { private static final String TAG = "ActivityInstrumentationRule"; private final Class<T> mActivityClass; public Instrumentation getInstrumentation() { return mInstrumentation; } private Instrumentation mInstrumentation; private boolean mInitialTouchMode = false; private boolean mLaunchActivity = false; private T mActivity; /** * Similar to {@link #MyActivityTestRule(Class, boolean, boolean)} but with "touch mode" disabled. * * @param activityClass The activity under test. This must be a class in the instrumentation * targetPackage specified in the AndroidManifest.xml * @see MyActivityTestRule#MyActivityTestRule(Class, boolean, boolean) */ public MyActivityTestRule(Class<T> activityClass) { this(activityClass, false); } /** * Similar to {@link #MyActivityTestRule(Class, boolean, boolean)} but defaults to launch the * activity under test once per * <a href="http://junit.org/javadoc/latest/org/junit/Test.html"><code>Test</code></a> method. * It is launched before the first * <a href="http://junit.sourceforge.net/javadoc/org/junit/Before.html"><code>Before</code></a> * method, and terminated after the last * <a href="http://junit.sourceforge.net/javadoc/org/junit/After.html"><code>After</code></a> * method. * * @param activityClass The activity under test. This must be a class in the instrumentation * targetPackage specified in the AndroidManifest.xml * @param initialTouchMode true if the Activity should be placed into "touch mode" when started * @see MyActivityTestRule#MyActivityTestRule(Class, boolean, boolean) */ public MyActivityTestRule(Class<T> activityClass, boolean initialTouchMode) { this(activityClass, initialTouchMode, true); } /** * Creates an {@link MyActivityTestRule} for the Activity under test. * * @param activityClass The activity under test. This must be a class in the instrumentation * targetPackage specified in the AndroidManifest.xml * @param initialTouchMode true if the Activity should be placed into "touch mode" when started * @param launchActivity true if the Activity should be launched once per * <a href="http://junit.org/javadoc/latest/org/junit/Test.html"> * <code>Test</code></a> method. It will be launched before the first * <a href="http://junit.sourceforge.net/javadoc/org/junit/Before.html"> * <code>Before</code></a> method, and terminated after the last * <a href="http://junit.sourceforge.net/javadoc/org/junit/After.html"> * <code>After</code></a> method. */ public MyActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) { mActivityClass = activityClass; mInitialTouchMode = initialTouchMode; mLaunchActivity = launchActivity; mInstrumentation = InstrumentationRegistry.getInstrumentation(); } /** * Override this method to set up Intent as if supplied to * {@link android.content.Context#startActivity}. * <p> * The default Intent (if this method returns null or is not overwritten) is: * action = {@link Intent#ACTION_MAIN} * flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} * All other intent fields are null or empty. * * @return The Intent as if supplied to {@link android.content.Context#startActivity}. */ protected Intent getActivityIntent() { return new Intent(Intent.ACTION_MAIN); } /** * Override this method to execute any code that should run before your {@link Activity} is * created and launched. * This method is called before each test method, including any method annotated with * <a href="http://junit.sourceforge.net/javadoc/org/junit/Before.html"><code>Before</code></a>. */ protected void beforeActivityLaunched() { // empty by default } /** * Override this method to execute any code that should run after your {@link Activity} is * launched, but before any test code is run including any method annotated with * <a href="http://junit.sourceforge.net/javadoc/org/junit/Before.html"><code>Before</code></a>. * <p> * Prefer * <a href="http://junit.sourceforge.net/javadoc/org/junit/Before.html"><code>Before</code></a> * over this method. This method should usually not be overwritten directly in tests and only be * used by subclasses of MyActivityTestRule to get notified when the activity is created and * visible but test runs. */ protected void afterActivityLaunched() { // empty by default } /** * Override this method to execute any code that should run after your {@link Activity} is * finished. * This method is called after each test method, including any method annotated with * <a href="http://junit.sourceforge.net/javadoc/org/junit/After.html"><code>After</code></a>. */ protected void afterActivityFinished() { // empty by default } /** * @return The activity under test. */ public T getActivity() { if (mActivity == null) { Log.w(TAG, "Activity wasn't created yet"); } return mActivity; } @Override public Statement apply(final Statement base, Description description) { return new ActivityStatement(super.apply(base, description)); } /** * Launches the Activity under test. * <p> * Don't call this method directly, unless you explicitly requested not to launch the Activity * manually using the launchActivity flag in * {@link MyActivityTestRule#MyActivityTestRule(Class, boolean, boolean)}. * <p> * Usage: * <pre> * &#064;Test * public void customIntentToStartActivity() { * Intent intent = new Intent(Intent.ACTION_PICK); * mActivity = mActivityRule.launchActivity(intent); * } * </pre> * @param startIntent The Intent that will be used to start the Activity under test. If * {@code startIntent} is null, the Intent returned by * {@link MyActivityTestRule#getActivityIntent()} is used. * @return the Activity launched by this rule. * @see MyActivityTestRule#getActivityIntent() */ public T launchActivity(@Nullable Intent startIntent) { // set initial touch mode mInstrumentation.setInTouchMode(mInitialTouchMode); final String targetPackage = mInstrumentation.getTargetContext().getPackageName(); // inject custom intent, if provided if (null == startIntent) { startIntent = getActivityIntent(); if (null == startIntent) { Log.w(TAG, "getActivityIntent() returned null using default: " + "Intent(Intent.ACTION_MAIN)"); startIntent = new Intent(Intent.ACTION_MAIN); } } startIntent.setClassName(targetPackage, mActivityClass.getName()); startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Log.d(TAG, String.format("Launching activity %s", mActivityClass.getName())); beforeActivityLaunched(); // The following cast is correct because the activity we're creating is of the same type as // the one passed in mActivity = mActivityClass.cast(mInstrumentation.startActivitySync(startIntent)); mInstrumentation.waitForIdleSync(); afterActivityLaunched(); return mActivity; } // Visible for testing void setInstrumentation(Instrumentation instrumentation) { mInstrumentation = checkNotNull(instrumentation, "instrumentation cannot be null!"); } void finishActivity() { if (mActivity != null) { mActivity.finish(); mActivity = null; } } /** * <a href="http://junit.org/apidocs/org/junit/runners/model/Statement.html"> * <code>Statement</code></a> that finishes the activity after the test was executed */ private class ActivityStatement extends Statement { private final Statement mBase; public ActivityStatement(Statement base) { mBase = base; } @Override public void evaluate() throws Throwable { try { if (mLaunchActivity) { mActivity = launchActivity(getActivityIntent()); } mBase.evaluate(); } finally { finishActivity(); afterActivityFinished(); } } } 

    }

Well, to be honest, it's standard ActivityTestRule with additional getter getInstrumentation() , which I would used in my test class.

  1. Create a new Java class - it would be your test class and put the code below:

     @RunWith(AndroidJUnit4.class) public class MainActivityTest { private Solo solo; private static final String MAIN_ACTIVITY = MainActivity.class.getSimpleName(); @Rule public MyActivityTestRule<MainActivity> mActivityRule = new MyActivityTestRule<>(MainActivity.class); @Before public void setUp() throws Exception { solo = new Solo(mActivityRule.getInstrumentation(), mActivityRule.getActivity()); } @Test public void checkIfMainActivityIsProperlyDisplayed() throws InterruptedException { solo.waitForActivity("MainActivity", 2000); solo.assertCurrentActivity(mActivityRule.getActivity().getString( R.string.error_no_class_def_found, MAIN_ACTIVITY), MAIN_ACTIVITY); solo.getText("Hello World").isShown(); } } 

As you see it's not difficult as might be.

Hope it will help

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM