Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Espresso Tests for phone and tablet

My setup: - Android App with Phone and Tablet Version - I am using Android Espresso for UI-Tests (now only for phone version, with phone at buildagent)

What I want to do: - Now I want Espresso to distinguish between tests for phone and tablet - So Test A should be only execute by a tablet, Test B should only be executed by a phone and Test C both - Tests should be executable via gradle task

like image 371
true-mt Avatar asked Oct 07 '14 08:10

true-mt


People also ask

What is espresso testing in Android?

The Espresso Test Recorder tool lets you create UI tests for your app without writing any test code. By recording a test scenario, you can record your interactions with a device and add assertions to verify UI elements in particular snapshots of your app.

What is Expresso in mobile testing?

Espresso created by Google is a native framework for Android automated testing. The tool is a part of the Android SDK and is easy to use for native mobile development. Thanks to Espresso, you can create tests that are close to the Android app's logic.


1 Answers

Three options, all of which are executable via gradlew connectedAndroidTest or custom gradle tasks:

1. Use org.junit.Assume

From Assumptions with assume - junit-team/junit Wiki - Github:

The default JUnit runner treats tests with failing assumptions as ignored. Custom runners may behave differently.

Unfortunately, the android.support.test.runner.AndroidJUnit4 (com.android.support.test:runner:0.2) runner treats failing assumptions as failed tests.

Once this behavior is fixed, the following would work (see Option 3 below for isScreenSw600dp() source):

Phone only: all test methods in the class

    @Before
    public void setUp() throws Exception {
        assumeTrue(!isScreenSw600dp());
        // other setup
    }

Specific test methods

    @Test
    public void testA() {
        assumeTrue(!isScreenSw600dp());
        // test for phone only
    }
    
    @Test
    public void testB() {
        assumeTrue(isScreenSw600dp());
        // test for tablet only
    }

2. Use a custom JUnit Rule

From A JUnit Rule to Conditionally Ignore Tests:

This led us to creating a ConditionalIgnore annotation and a corresponding rule to hook it into the JUnit runtime. The thing is simple and best explained with an example:

public class SomeTest {
  @Rule
  public ConditionalIgnoreRule rule = new ConditionalIgnoreRule();

  @Test
  @ConditionalIgnore( condition = NotRunningOnWindows.class )
  public void testFocus() {
    // ...
  }
}

public class NotRunningOnWindows implements IgnoreCondition {
  public boolean isSatisfied() {
    return !System.getProperty( "os.name" ).startsWith( "Windows" );
  }
}

ConditionalIgnoreRule code here: JUnit rule to conditionally ignore test cases.

This approach can be easily modified to implement the isScreenSw600dp() method in Option 3 below.


3. Use conditionals in the test methods

This is the least elegant option, particularly because entirely skipped tests will be reported as passed, but it's very easy to implement. Here's a full sample test class to get you started:

import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;

@RunWith(AndroidJUnit4.class)
public class DeleteMeTest extends ActivityInstrumentationTestCase2<MainActivity> {
    private MainActivity mActivity;
    private boolean mIsScreenSw600dp;

    public DeleteMeTest() {
        super(MainActivity.class);
    }

    @Before
    public void setUp() throws Exception {
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        setActivityInitialTouchMode(false);
        mActivity = this.getActivity();
        mIsScreenSw600dp = isScreenSw600dp();
    }

    @After
    public void tearDown() throws Exception {
        mActivity.finish();
    }

    @Test
    public void testPreconditions() {
        onView(withId(R.id.your_view_here))
                .check(matches(isDisplayed()));
    }

    @Test
    public void testA() {
        if (!mIsScreenSw600dp) {
            // test for phone only
        }
    }

    @Test
    public void testB() {
        if (mIsScreenSw600dp) {
            // test for tablet only
        }
    }

    @Test
    public void testC() {
        if (mIsScreenSw600dp) {
            // test for tablet only
        } else {
            // test for phone only
        }
        
        // test for both phone and tablet
    }

    private boolean isScreenSw600dp() {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        mActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        float widthDp = displayMetrics.widthPixels / displayMetrics.density;
        float heightDp = displayMetrics.heightPixels / displayMetrics.density;
        float screenSw = Math.min(widthDp, heightDp);
        return screenSw >= 600;
    }
}
like image 134
unrulygnu Avatar answered Sep 21 '22 10:09

unrulygnu