androidjunit4android-unit-testing

Following Android docs on unit testing and failing


I am trying to run the simple unit test by following the example here:

https://developer.android.com/training/testing/unit-testing/local-unit-tests

import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Test;

import static com.google.common.truth.Truth.assertThat;

public class UnitTestSampleJava {
    private static final String FAKE_STRING = "HELLO_WORLD";
    private Context context = ApplicationProvider.getApplicationContext();

    @Test
    public void readStringFromContext_LocalizedString() {
        // Given a Context object retrieved from Robolectric...
        ClassUnderTest myObjectUnderTest = new ClassUnderTest(context);

        // ...when the string is returned from the object under test...
        String result = myObjectUnderTest.getHelloWorldString();

        // ...then the result should be the expected one.
        assertThat(result).isEqualTo(FAKE_STRING);
    }
}

I have a brand new project and I set the gradle files as specified, then I created a test with this line:

private Context context = ApplicationProvider.getApplicationContext();

and I get an exception on that line number stating:

java.lang.IllegalStateException: No instrumentation registered! Must run under a registering instrumentation.

However, this was listed in the docs as a local unit test and not an instrumented test.


Solution

  • This will be common knowledge for experienced people, but I will write this for those who are just starting out like me.

    A lot of the only tutorials were very confusing and I could not get them to compile or work because of different versions of everything.

    The first thing I didn't realize is that there are two different Gradle functions, testImplementation and androidTestImplementation. The function "testImplementation" is for plain unit tests and the function "androidTestImplementation" is for instrumented unit tests (unit test but running on a physical device).

    So when you see the command in Gradle under dependencies:

    testImplementation 'junit:junit:4.12'
    

    That's only including JUnit 4.12 for unit tests in the default app/src/test folder, not the app/src/androidTest folder.

    If you follow the tutorial I linked above (which is probably out of date or simply incorrect) is that 'androidx.test:core:1.0.0' has integrated Robolectric, and you are using Robolectric without calling functions or importing directly.

    You don't need to add the @RunWith annotation because in the Gradle file the tutorial has you add:

    defaultConfig {
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    ...
    }
    

    Despite this, I could not escape the exception I described by following the tutorial. So I had to include Robolectric directly:

    testImplementation "org.robolectric:robolectric:4.3.1"
    

    and this is my unit test class:

    import android.content.Context;
    
    import androidx.test.core.app.ApplicationProvider;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.robolectric.RobolectricTestRunner;
    import org.robolectric.annotation.Config;
    
    import static org.junit.Assert.assertTrue;
    
    @Config(maxSdk = 29)
    @RunWith(RobolectricTestRunner.class)
    public class UnitTestSample {
        private static final String FAKE_STRING = "HELLO_WORLD";
    
    
        @Test
        public void clickingButton_shouldChangeResultsViewText() throws Exception {
            Context context = ApplicationProvider.getApplicationContext();
    
            assertTrue(true);
        }
    }
    

    Another thing I had to do was set the SDK to 29 with @Config, because Robolectric 4.3.1 doesn't support Android API level 30.