androidandroid-gradle-pluginrobolectricrobolectric-gradle-plugin

How to use findViewById() in robolectric


I simply want to test with robolectric if a certain view is visible in a fragment. My unit test looks like this:

ActivityController controller = Robolectric.buildActivity(FragmentActivity.class);
FragmentActivity activity = (FragmentActivity) controller.create().start().resume().visible().get();

F fragment = new MyFragment();
activity.getSupportFragmentManager().beginTransaction()
        .add(fragment, FRAGMENT_TAG).commit();


View view = fragment.getView().findViewById(R.id.my_view);
assertEquals(view.getVisibility(), View.VISIBLE);

I'm using the latest android gradle plugin 1.1.3, robolectirc 2.4 and robolectric gradle plugin 1.0.1 and my unit test is in the test folder (not androidTest). I can't compile that code, because the compiler can't resolve R.java.

My build.gradle:

buildscript {
  repositories {
    jcenter()
  }

  dependencies {
    classpath 'com.android.tools.build:gradle:1.1.3'
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
  }
}

apply plugin: 'com.android.library'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'org.robolectric'


android { ... }

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])

  // Testing
  testCompile 'org.robolectric:robolectric:2.4'
  testCompile 'junit:junit:4.12'

  // Other dependencies
  ...
}

How do I write such a unit test with robolectric?

Update: Here is the complete code:

public class TestFragment extends Fragment {

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_listview_ptr, container, false);
  }
}


public class MyFragmentTest {

  private static final String FRAGMENT_TAG = "fragment";
  private ActivityController controller;
  private FragmentActivity activity;

  @Test
  protected void displaysContentView(boolean pullToRefreshSupported) {

    controller = Robolectric.buildActivity(FragmentActivity.class);
    activity = (FragmentActivity) controller.create().start().resume().visible().get();
    Fragment fragment = new TestFragment();

    FragmentManager manager = activity.getSupportFragmentManager();
    manager.beginTransaction()
        .add(fragment, FRAGMENT_TAG).commit();

    // Compile errors here
    View loadingView = fragment.getView().findViewById(R.id.loadingView);
    View contentView = fragment.getView().findViewById(R.id.contentView);
    View errorView = fragment.getView().findViewById(R.id.loadingView);

    Assert.assertNotSame(loadingView.getVisibility(), View.VISIBLE);
    Assert.assertNotSame(errorView.getVisibility(), View.VISIBLE);
    Assert.assertEquals(contentView.getVisibility(), View.VISIBLE);
  }
}

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">


<android.support.v4.widget.SwipeRefreshLayout
      android:id="@+id/pull_to_refresh"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

    <ListView
        android:id="@+id/contentView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#00000000"
        android:divider="@null"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:listSelector="@color/transparent"
        android:drawSelectorOnTop="true"
        android:smoothScrollbar="false"
        android:scrollbars="none"/>
</android.support.v4.widget.SwipeRefreshLayout>

<TextView
      android:id="@+id/errorView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:visibility="gone"
      android:text="@string/error_loading_retry"
      android:layout_gravity="center"
      android:gravity="center"
      android:layout_centerInParent="true"
      android:drawableTop="@drawable/error_no_connection"
      android:drawablePadding="12dp"
      android:textColor="@color/gray_dark"
      android:padding="16dp"
      />

<fr.castorflex.android.circularprogressbar.CircularProgressBar
      android:id="@+id/loadingView"
      android:layout_width="40dp"
      android:layout_height="40dp"
      android:indeterminate="true"
      android:layout_gravity="center"
      android:layout_centerInParent="true"
      android:visibility="gone"
      />

</FrameLayout>

The code can be found here: https://github.com/sockeqwe/RobolectircTest


Solution

  • Update:

    I would suggest to go ahead and update to Robolectric 3.0.

    Annotate your classes with:

    @RunWith(CustomRobolectricRunner.class)
    @Config(emulateSdk = 21, reportSdk = 21)
    

    RobolectricGradleTestRunner.java:

    https://github.com/nenick/AndroidStudioAndRobolectric/blob/master/app/src/test/java/com/example/myapplication/CustomRobolectricRunner.java

    Update your build.gradle:

    apply plugin: 'com.android.application' // <-- for some reason, com.android.library is not working correctly
    apply plugin: 'org.robolectric'
    
    android {
        compileSdkVersion 22
        buildToolsVersion "22.0.0"
    
        defaultConfig {
            minSdkVersion 14
            targetSdkVersion 22
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        compile 'com.android.support:appcompat-v7:22.0.0'
    
        testCompile 'junit:junit:4.12'
        testCompile 'org.apache.maven:maven-ant-tasks:2.1.3'
        testCompile('org.robolectric:shadows-support-v4:3.0-SNAPSHOT') {
            exclude group: 'commons-logging', module: 'commons-logging'
            exclude group: 'org.apache.httpcomponents', module: 'httpclient'
        }
    }
    

    Original:

    Using Robolectric.buildActivity(FragmentActivity.class); is for testing Activitys.

    Please edit your MyFragmentTest to look like this:

    @RunWith(CustomRobolectricRunner.class)
    @Config(emulateSdk = 21, reportSdk = 21)
    public class MyFragmentTest {
    
      @Test
      public void testAppFragmentStart() {
        final TestFragment fragment = new TestFragment();
    
        SupportFragmentTestUtil.startFragment(fragment, FragmentActivity.class);
    
        // My test examples - hamcrest matchers
        Assert.assertThat(fragment, CoreMatchers.not(CoreMatchers.nullValue()));
        Assert.assertThat(fragment.getView(), CoreMatchers.not(CoreMatchers.nullValue()));
        Assert.assertThat(fragment.getActivity(), CoreMatchers.not(CoreMatchers.nullValue()));
        Assert.assertThat(fragment.getActivity(), CoreMatchers.instanceOf(FragmentActivity.class));
    
        // Your tests
        View loadingView = fragment.getView().findViewById(R.id.loadingView);
        View contentView = fragment.getView().findViewById(R.id.contentView);
        View errorView = fragment.getView().findViewById(R.id.errorView);
    
        Assert.assertNotSame(loadingView.getVisibility(), View.VISIBLE);
        Assert.assertNotSame(errorView.getVisibility(), View.VISIBLE);
        Assert.assertEquals(contentView.getVisibility(), View.VISIBLE);
      }
    }