home.


Tagged: android-testing


Android testing: Click an item in a ListView

There are two ways to do this. The Andrioid instrumentation and the Robotium way.

final ListView listLiew = (ListView) activity.findViewById(R.id.your_list_view);
runTestOnUiThread(new Runnable() {
    @Override
    public void run() {
       listLiew.performItemClick(listLiew, POSTITION_IN_LIST, listLiew.getItemIdAtPosition(POSTITION_IN_LIST));
    }
});

You get a reference to the list view, and call performItemClick.

Robotium is simpler, using just

solo.clickInList(POSITION_IN_LIST, LIST_NUMBER_IN_PAGE); 

This means you must know what number the list is in your page – which you may not be able to be sure of easily.

Obviously if you just have one list, then this method works the best.

The source of Robotium’s method is at: https://github.com/jayway/robotium/blob/master/robotium-solo/src/main/java/com/jayway/android/robotium/solo/Clicker.java

android android-testing android-robotium

Android: Testing fragments

Update: I would not recomment this anymore. Although it may work, there are new mockito testing tutorials on the Android documentation site, which you should look at first. And, these days, I use the MVP architecture, allowing me to place all the logic in the presenter layer, which I then test via normal Java unit testing tools in isolation from the Android specfic code, and test the UI, including the fragments, with the UI testing library and framework, Espresso.

If you want to test a fragment in isolation, you need to create a Test FragmentActivity so your test can use that. The test activity will look something like this. Remember to declare it in your application’s manifest:

 public class TestFragmentActivity extends FragmentActivity {
   @Override
   protected void onCreate(Bundle arg0) {
     super.onCreate(arg0);
     setContentView(R.layout.activity_fortests);
   }
 }

Layout:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <LinearLayout
        android:id="@+id/activity_test_fragment_linearlayout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        />
 </RelativeLayout>

AndroidManifest:

 ...
 <activity
  android:name="your.package.name.TestFragmentActivity">
 </activity>
 ...

Then in your test project, you can have a class like this to start the fragment:

  public class FrameworkObjectsGeneratorFragmentTest 
      extends ActivityInstrumentationTestCase2<TestFragmentActivity> {
    private TestFragmentActivity mActivity;

    public FrameworkObjectsGeneratorFragmentTest() {
      super(TestFragmentActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
      super.setUp();
      mActivity = getActivity();
    }

    private Fragment startFragment(Fragment fragment) {
      FragmentTransaction transaction = mActivity.getSupportFragmentManager().beginTransaction();
      transaction.add(R.id.activity_test_fragment_linearlayout, fragment, "tag");
      transaction.commit();
      getInstrumentation().waitForIdleSync();
      Fragment frag = mActivity.getSupportFragmentManager().findFragmentByTag("tag");
      return frag;
    }

   public void testFragment() {
      FrameworkObjectsGeneratorFragment fragment = new FrameworkObjectsGeneratorFragment() {
         //Override methods and add assertations here.
      };

      Fragment frag = startFragment(fragment);
    }
  }

The startFragment() method adds a fragment you specify to the ViewGroup in the TestActivity.

The good thing about testing fragments, as opposed to Activities, is that you can extends the Fragment to override protected fields and methods within which you can add assertions.

android android-testing android-fragments

Running tests on Android through adb

Although you can run test through Eclipse and via Ant, running them directly though adb is often the best option since

  • when you’re running them on a build server Eclipse’s method won’t be available to you, and;
  • the default ant ‘test’ target doesn’t take into account non-standard source directories or non-standard test runners for example.

It’s simply enough using adb, as soon as you’ve installed the test project on your device/emulator:

adb shell am instrument -w your.test.project.package/android.test.InstrumentationTestRunner

The -w tag tells it to wait and print out the results. The package is what you’ve defined in the AndroidManifest.xml in your Android test project. The text after that is the test runner, the default one in this case.

The default test runner does not output junit XML format, unforunately. But there are alternatives, such as https://code.google.com/p/the-missing-android-xml-junit-test-runner/ If you do use this, then your adb command will be, after you’ve included the jar in your test projects’s build:

adb shell am instrument -w your.test.project.package/pl.polidea.instrumentation.PolideaInstrumentationTestRunner

Then you can use another build target to get the XML junit data off the device, which is located in the data/data/your.app/files directory by default.

Of course, you can put the above command in an ant target:

 <target name="instrument">
    <echo level="info">Running instrumentation tests</echo>
      <exec executable="adb" failonerror="true">
           <arg value="shell" />
           <arg value="am" />
           <arg line="instrument -w your.test.package/pl.polidea.instrumentation.PolideaInstrumentationTestRunner" />
      </exec>
 </target>

To pull the XML junit files, these ant commands will help:

  <mkdir dir="junit-results" />
  <exec executable="adb" failonerror="true" dir="junit-results">
      <arg value="pull" />
      <arg value="/data/data/your.actual.apps.package/files/" />
  </exec>
android android-adb android-testing ant ant-exec

android-robolectric

Setting up Robolectric is such a ballache.

  1. In your main project, create a test directory at its root project level.
  2. Create a new normal Java project, removing the ‘src’ directory in the setup screens, and linking to the test directory you created above, and adding your main project as a dependency
  3. Add Junit4, your Android API jar, the Android maps jar and the Robolectric jar (the one with all dependencies) to your build path for the java project.
  4. Create a new run configuration for a normal junit configuration, with junit 4 as its test runner, running all the tests in your java project, and with the eclipse junit launcher. And under the arguments tab, set the working directory to be your main project.
  5. Create this test class and use the run configuration you made above:

      package com.example.robolectric;
      import static org.hamcrest.CoreMatchers.equalTo;
      import static org.junit.Assert.assertThat;
      import org.denevell.twunter.MainActivity;
      import org.denevell.twunter.R;import org.junit.Test;
      import org.junit.runner.RunWith; 
      import com.xtremelabs.robolectric.RobolectricTestRunner; 
    
      @RunWith(RobolectricTestRunner.class)
      public class TestTest {
         @Test
         public void shouldHaveHappySmiles() throws Exception {
             String hello = new MainActivity().getResources().getString(R.string.hello_world);
             assertThat(hello, equalTo("Hello world!"));
         }
      }
    
android robolectric robolectric-setup android-testing

Page 1 of 1