23

I got some of my old tests running with Android Studio 1.1.0's new unit test support feature. When running gradlew testDebug the tests are run, but all of the tests that require a Context fail because getContext (AndroidTestCase) / getInstrumentation.getContext() (InstrumentationTestCase) both return null.

How can I solve this?

Here's two variants I've tried:

import android.content.Context;
import android.test.InstrumentationTestCase;

public class TestTest extends InstrumentationTestCase {

    Context context;

    public void setUp() throws Exception {
        super.setUp();

        context = getInstrumentation().getContext();

        assertNotNull(context);

    }

    public void testSomething() {

        assertEquals(false, true);
    }  

}

and

import android.content.Context;
import android.test.AndroidTestCase;

public class TestTest extends AndroidTestCase {

    Context context;

    public void setUp() throws Exception {
        super.setUp();

        context = getContext();

        assertNotNull(context);

    }

    public void testSomething() {

        assertEquals(false, true);
    }

}

This is my module's build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.0"

    testOptions {
        unitTests.returnDefaultValues = true
    }

    defaultConfig {
        applicationId "com.example.test.penistest"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    testCompile 'junit:junit:4.12'
}

and here the build.gradle for the project:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

EDIT: My tests all worked before upgrading to AS 1.1.0 and ran on a device / emulator.

EDIT:

Heres 2 screenshots of failing InstrumentationTestCase and AndroidTestCase:

enter image description here

enter image description here

fweigl
  • 21,278
  • 20
  • 114
  • 205

6 Answers6

43

Updated - Please use Espresso for writing instrumentation tests

Newer Examples:

I got these working without deploying to a device. Put the tests in the /src/main/test/ folder.

Here are newer examples, I took your examples and tested them in my own temporary test project. I ran the tests via command line: ./gradlew clean test. Please read more here: https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support.

Top build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

App build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.0"

    defaultConfig {
        applicationId "com.test"
        minSdkVersion 9
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    testOptions { // <-- You need this
        unitTests {
            returnDefaultValues = true
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'

    testCompile 'junit:junit:4.12' // <-- You need this
}

Basic Tests:

InstrumentationTestCaseTest to test Context and Assertions.

import android.content.Context;
import android.test.InstrumentationTestCase;
import android.test.mock.MockContext;

public class InstrumentationTestCaseTest extends InstrumentationTestCase {

    Context context;

    public void setUp() throws Exception {
        super.setUp();

        context = new MockContext();

        assertNotNull(context);

    }

    public void testSomething() {

        assertEquals(false, true);
    }

}

ActivityTestCase to test your Resources.

import android.content.Context;
import android.content.res.Resources;
import android.test.ActivityTestCase;

public class ActivityTestCaseTest extends ActivityTestCase {

    public void testFoo() {

        Context testContext = getInstrumentation().getContext();
        Resources testRes = testContext.getResources();

        assertNotNull(testRes);
        assertNotNull(testRes.getString(R.string.app_name));
    }
}

AndroidTestCase to test Context and Assertions.

import android.content.Context;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;

public class AndroidTestCaseTest extends AndroidTestCase {

    Context context;

    public void setUp() throws Exception {
        super.setUp();

        context = new MockContext();

        setContext(context);

        assertNotNull(context);

    }

    // Fake failed test
    public void testSomething()  {
        assertEquals(false, true);
    }
}

Googling Old Examples:

After Googling a lot bout this error, I believe your bet is to use getInstrumentation().getContext().getResources().openRawResource(R.raw.your_res). or something similar in order to test your resources.

Using InstrumentationTestCase:

Test Resources:

public class PrintoutPullParserTest extends InstrumentationTestCase {

    public void testParsing() throws Exception {
        PrintoutPullParser parser = new PrintoutPullParser();
        parser.parse(getInstrumentation().getContext().getResources().getXml(R.xml.printer_configuration));
    }
}

Source: https://stackoverflow.com/a/8870318/950427 and https://stackoverflow.com/a/16763196/950427

Using ActivityTestCase:

Test Resources:

public class Test extends ActivityTestCase {

   public void testFoo() {  

      // .. test project environment
      Context testContext = getInstrumentation().getContext();
      Resources testRes = testContext.getResources();
      InputStream ts = testRes.openRawResource(R.raw.your_res);

      assertNotNull(testRes);
   }    
}

Source: https://stackoverflow.com/a/9820390/950427

Using AndroidTestCase:

Getting the Context (a simple hack):

private Context getTestContext() {
    try {
        Method getTestContext = ServiceTestCase.class.getMethod("getTestContext");
        return (Context) getTestContext.invoke(this);
    } catch (final Exception exception) {
        exception.printStackTrace();
        return null;
    }
}

Source: https://stackoverflow.com/a/14232913/950427

But, if you look a the source code of AndroidTestCase, it looks like you need to set a Context yourself:

Source: http://alvinalexander.com/java/jwarehouse/android/core/java/android/test/AndroidTestCase.java.shtml

Community
  • 1
  • 1
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73276/discussion-between-jared-burrows-and-ascorbin). – Jared Burrows Mar 18 '15 at 19:13
  • @Ascorbin http://wikisend.com/download/284136/AndroidTestProject_jaredsburrows.zip. `griddle clean test` or in Android Studio, File -> "Import Project" -> Click on the `build.gradle`. – Jared Burrows Mar 18 '15 at 19:41
  • @Ascorbin, the bounty ends in 10 hours, did you try the project I sent? – Jared Burrows Mar 19 '15 at 01:29
  • Yes I did, did not work. You sure have earned the bounty, thanks for your effort! – fweigl Mar 19 '15 at 09:03
  • Nope, they didn't, failed exactly the same as mine. I have no idea what the reason could be, I'll probably wait for the next update on AS until I try to fix it again. – fweigl Mar 19 '15 at 10:38
  • Do you have the latest update(Android Studio 1.1.0 Build 135.1470770)? I don't understand why it should matter if you also ran via command line: `gradlew clean test`. You are using the same versions of plugins as I am. – Jared Burrows Mar 19 '15 at 10:58
  • The link you provided (new test project) gives me a mp4 video instead of code – Damnum Apr 12 '15 at 17:51
  • @Damnum That is very weird. I am removing that link. I have now deleted that source. – Jared Burrows Apr 12 '15 at 18:38
  • This is already deprecated. See latest response; it seems that is containing the latest method to get context. – Emil Pana Jan 12 '17 at 13:43
20

With the Android Testing Support Library, you can

  • get test apk context with InstrumentationRegistry.getContext()
  • get app apk context with InstrumentationRegistry.getTargetContext()
  • get Instrumentation with InstrumentationRegistry.getInstrumentation()

See the bottom of the linked page for how to add Testing Support library to your project.

Stan Kurdziel
  • 5,476
  • 1
  • 43
  • 42
taynguyen
  • 2,961
  • 1
  • 26
  • 26
  • 1
    So what's the difference between these contexts? – IgorGanapolsky Oct 25 '16 at 17:39
  • 2
    @IgorGanapolsky there are two APKs installed when running Android tests. One which is the APK of your applications and second which is the APK of the tests. So therefore "app APK context" and "test APK context". – vilpe89 Mar 03 '17 at 14:45
11

Here is a recent way to setup (unit) instrumentation tests

Setup

In your build.gradle add:

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

and the following dependencies:

// Instrumentation tests
androidTestImplementation "com.android.support.test:runner:$supportTestRunnerVersion"
// To use assertThat syntax
androidTestImplementation "org.assertj:assertj-core:$assertJVersion"

Example class

public class Example {

    public Object doSomething() {
        // Context is used here
    }

}

Example test

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

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

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(AndroidJUnit4.class)
public class ExampleTest {

    private Context context;

    @Before
    public void setUp() {
        // In case you need the context in your test
        context = InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void doSomething() {
        Example example = new Example();
        assertThat(example.doSomething()).isNotNull();
    }

}

Documentation

JJD
  • 50,076
  • 60
  • 203
  • 339
4

I was receiving an error when trying to make calls to SQLite using @taynguyen answer, so instead of:

InstrumentationRegistry.getContext()

I used:

InstrumentationRegistry.getTargetContext()

In order to get my target application context instead of the Instrumentation context.

Dev D
  • 41
  • 3
1

Context needs to refer to something that extends Context such as an Activity or Application class.

Context context = new Activity(); 

Another alternative is to use Robolectric.Application.

TTransmit
  • 3,270
  • 2
  • 28
  • 43
  • I have a similar issue and isn't the whole point of "AndroidTestCase" to be able to test an activity-less class/project? To be clear: I have a library (activity less) I'm trying to test. It uses of the "Context" (passed as a parameter in the library constructor), so I shouldn't have to use any activity if I understand correctly. – Pelpotronic Mar 13 '15 at 15:51
  • While new Activity() of course gives me a Context, I can not access my resources (Strings, Assets) from it unfortunately. – fweigl Mar 13 '15 at 15:59
  • I have found that I can access resources with `new Activity().getResources`. I'm not sure if there is some aspect of my setup that is causing this to work for me and not for you. – TTransmit Mar 13 '15 at 16:04
  • 1
    Why not use `new MockContext()` from instrumentation package? – IgorGanapolsky Oct 25 '16 at 17:41
  • Good point. For some purposes, I have found you can also use `Mockito.mock(Context.class)`. The most appropriate choice will probably depend on what you are generally using in the rest of the test class. – TTransmit Oct 26 '16 at 09:43
1

getInstrumentation().getContext() is now deprecated you should use this InstrumentationRegistry.getInstrumentation().getTargetContext() you can find more details here androidx.test.InstrumentationRegistry is deprecated

ilatyphi95
  • 555
  • 5
  • 22