Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting context in AndroidTestCase or InstrumentationTestCase in Android Studio's Unit Test feature

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

like image 797
fweigl Avatar asked Mar 10 '15 10:03

fweigl


3 Answers

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

like image 172
Jared Burrows Avatar answered Nov 10 '22 23:11

Jared Burrows


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.

like image 33
taynguyen Avatar answered Nov 11 '22 00:11

taynguyen


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

  • Building Instrumented Unit Tests | Android Developers
like image 37
JJD Avatar answered Nov 10 '22 23:11

JJD