43

I have an Activity that pulls an object from an Application extended class (application context) from within the OnCreate() method.

When unit testing this activity, the object needed isn't there because it is populated from a previous Activity and stored in the above mentioned application context.

Needless to say, when I call getActivity() from within my ActivityInstrumentationTestCase2 extended test case I get a null pointer exception.

How can I populate the context before an activity is started and have it available to that Activity?

Updated: After a bit of digging I found: this.getInstrumentation().getTargetContext() and then cast it to the type of my Application extended class. But I get a class cast exception and the trace points to this:

04-04 21:02:27.036: INFO/TestRunner(431): started: testIt(edu.rockies.rockies.activity.courses.test.TopicTest)
04-04 21:02:27.126: INFO/TestRunner(431): failed: testIt(edu.rockies.rockies.activity.courses.test.TopicTest)
04-04 21:02:27.126: INFO/TestRunner(431): ----- begin exception -----
04-04 21:02:27.136: INFO/TestRunner(431): java.lang.ClassCastException: android.app.ApplicationContext
04-04 21:02:27.136: INFO/TestRunner(431):     at edu.rockies.rockies.activity.courses.test.TopicTest.setUp(TopicTest.java:27)
04-04 21:02:27.136: INFO/TestRunner(431):     at junit.framework.TestCase.runBare(TestCase.java:125)
04-04 21:02:27.136: INFO/TestRunner(431):     at junit.framework.TestResult$1.protect(TestResult.java:106)
04-04 21:02:27.136: INFO/TestRunner(431):     at junit.framework.TestResult.runProtected(TestResult.java:124)
04-04 21:02:27.136: INFO/TestRunner(431):     at junit.framework.TestResult.run(TestResult.java:109)
04-04 21:02:27.136: INFO/TestRunner(431):     at junit.framework.TestCase.run(TestCase.java:118)
04-04 21:02:27.136: INFO/TestRunner(431):     at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
04-04 21:02:27.136: INFO/TestRunner(431):     at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
04-04 21:02:27.136: INFO/TestRunner(431):     at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:430)
04-04 21:02:27.136: INFO/TestRunner(431):     at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
04-04 21:02:27.136: INFO/TestRunner(431): ----- end exception -----
04-04 21:02:27.156: INFO/TestRunner(431): finished: testIt(edu.rockies.rockies.activity.courses.test.TopicTest)

this.getInstrumentation().getTargetContext() is supposed to return an object of type context. But I get the android.app.ApplicationContext class cast exeption which doesn't make sense.

Update 2:

I did some more research and discovered this for android.app.Application

java.lang.Object
    android.content.Context
        android.app.ApplicationContext
            android.app.Application

But Google's own Android Javadoc refers to this:

java.lang.Object
    android.content.Context
        android.content.ContextWrapper
            android.app.Application

What's going on? Something's not right.

Update 3:

I have replaced the following line of code:

this.getInstrumentation().getTargetContext();

with this line of code.

this.getInstrumentation().getTargetContext().getApplicationContext();

Although the context resolves properly, it doesn't seem to be the same context as the activity's.

Salsero69
  • 2,160
  • 3
  • 23
  • 27
  • Did you try calling `getActivity().getApplication()`? – Macarse Apr 04 '11 at 21:18
  • 1
    I can't because the activity's OnCreate() method depends on data being in the context already. Calling getActivity() essentially calls the OnCreate() method which fails and thus generates a Null Pointer Exception. Hence my dilemma. – Salsero69 Apr 04 '11 at 21:47
  • Ok, my tests are running fine this morning. Not sure what's changed, but the latest update above (Update 3) seems to have resolved the issue. – Salsero69 Apr 05 '11 at 13:51
  • Your Update 3 made my first test work, but the second test in the class still failed. It worked when I left the call to getApplicationContext() out.. But Why? :| – Jolanda Verhoef Apr 19 '12 at 09:08

7 Answers7

61

Ok, this issue is resolved. To get access to the context before getActivity() has been called you need to call this function:

Context context = this.getInstrumentation().getTargetContext().getApplicationContext();
Salsero69
  • 2,160
  • 3
  • 23
  • 27
  • 6
    This is not so simple or maybe things have changed: I found out that this.getInstrumentation().getTargetContext() returns exactly my application context (I know this for sure because I have custom "MyApplication" class) AND .getApplicationContext() returns null. So my code which retrieves application context adapts for this case also, see https://github.com/andstatus/andstatus/blob/master/src/org/andstatus/app/data/MyPreferences.java , public static Context initialize(Context context_in, ... object ); - the context_in has .getApplicationContext() if called from the test classes – yvolk Mar 14 '13 at 06:19
12

With the newer UI testing framework getInstrumentation() is no longer available. One way to get hold of the Application object is to cast the application Context:

Application app = 
        (Application) InstrumentationRegistry
                .getTargetContext()
                .getApplicationContext();
friederbluemle
  • 33,549
  • 14
  • 108
  • 109
  • I need application and with your code i get this error: android.app.ContextImpl cannot be cast to android.app.Application – Mahdi Feb 17 '20 at 05:22
5

You can get the application context using the androidx.test.core.app.ApplicationProvider.getApplicationContext(). Cast that to your application and it should be the right context.

Joseph
  • 5,793
  • 4
  • 34
  • 41
3

You can call the static method for the Context:

Context context = InstrumentationRegistry.getTargetContext();

More details can be found here: https://developer.android.com/training/testing/integration-testing/index.html

Alécio Carvalho
  • 13,481
  • 5
  • 68
  • 74
3

In kotlin val context = InstrumentationRegistry.getInstrumentation().context worked for me.

enoler
  • 179
  • 1
  • 11
  • You might use `ApplicationProvider.getApplicationContext()` as well. Its a wrapper around `InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext()`. – Aaron Oct 01 '21 at 08:43
  • 1
    **target context** is better that context: `InstrumentationRegistry.getInstrumentation().targetContext` – Amir Hossein Aug 21 '22 at 11:52
2

Always use this.getInstrumentation().getTargetContext() to access the context of the application.

this.getInstrumentation().getTargetContext().getApplicationContext() is not same as this.getInstrumentation().getTargetContext()

I was running the automation in 4.0.X versions and most of the time getApplicationContext() was returning null context.

Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67
-2

Keep in mind we need some of the following, the test is androidTest and not unit.

  • Context
  • Read or Write on storage
  • Access Network
  • Or change any config to test your function

@RunWith(AndroidJUnit4::class)
class SomeInstrumentedTest {
    private val appContext = InstrumentationRegistry.getInstrumentation().targetContext

    @Test
    fun useAppContext() {
        // Context of the app under test.
        Assert.assertEquals("your.package", appContext.packageName)
    }
}

unit vs androidTest

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62