Android Unit Tests Requiring Context
Asked Answered
R

9

88

I am writing my first Android database backend and I'm struggling to unit test the creation of my database.

Currently the problem I am encountering is obtaining a valid Context object to pass to my implementation of SQLiteOpenHelper. Is there a way to get a Context object in a class extending TestCase? The solution I have thought of is to instantiate an Activity in the setup method of my TestCase and then assigning the Context of that Activity to a field variable which my test methods can access...but it seems like there should be an easier way.

Risteau answered 19/1, 2010 at 17:54 Comment(0)
S
43

You might try switching to AndroidTestCase. From looking at the docs, it seems like it should be able to provide you with a valid Context to pass to SQLiteOpenHelper.

Edit: Keep in mind that you probably have to have your tests setup in an "Android Test Project" in Eclipse, since the tests will try to execute on the emulator (or real device).

Sinegold answered 19/1, 2010 at 18:1 Comment(3)
when extending AndroidTestCase and then calling this.getContext(), null is returned. is that how it's supposed to work? I expected a rich Context to be returned that would work with SQLiteReynalda
AndroidTestCase is now deprecated, and it is recommended to use InstrumentationRegistry instead.Celle
android.support.test.InstrumentationRegistry is now depreciated as well. Google is depreciating stuff faster than you can type a stackoverfow comment.Cioffi
W
54

You can use InstrumentationRegistry methods to get a Context:

InstrumentationRegistry.getTargetContext() - provides the application Context of the target application.

InstrumentationRegistry.getContext() - provides the Context of this Instrumentation’s package.


For AndroidX use InstrumentationRegistry.getInstrumentation().getTargetContext() or InstrumentationRegistry.getInstrumentation().getContext().

New API for AndroidX: ApplicationProvider.getApplicationContext()

Waxen answered 20/5, 2016 at 16:20 Comment(7)
what dependency AndroidJUnit4.class comes from?Anaxagoras
ditto on needing a more complete example.Indian
This wouldn't be a unit test, but an integration test.Betroth
@birdy how can I use this together with JUnit5?Lolanthe
Update: use ApplicationProvider.getApplicationContext() insteadAvitzur
Anybody got the full syntax for Kotlin for using getApplicationContext?Cioffi
@Cioffi Here is the link for kotlin #8606111Cloth
S
43

You might try switching to AndroidTestCase. From looking at the docs, it seems like it should be able to provide you with a valid Context to pass to SQLiteOpenHelper.

Edit: Keep in mind that you probably have to have your tests setup in an "Android Test Project" in Eclipse, since the tests will try to execute on the emulator (or real device).

Sinegold answered 19/1, 2010 at 18:1 Comment(3)
when extending AndroidTestCase and then calling this.getContext(), null is returned. is that how it's supposed to work? I expected a rich Context to be returned that would work with SQLiteReynalda
AndroidTestCase is now deprecated, and it is recommended to use InstrumentationRegistry instead.Celle
android.support.test.InstrumentationRegistry is now depreciated as well. Google is depreciating stuff faster than you can type a stackoverfow comment.Cioffi
C
25

Your test is not a Unit test!!!

When you need

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

You are not writing a unit test.

You need to write your test in androidTest package

Calling answered 9/6, 2019 at 12:3 Comment(3)
You mean it's not a local test (but an instrumented test). A test in the androidTest package can very well be a unit test.Ault
how did you come to this idea or where did you read that, many times in unit test mock classes don't really do the job because they are fake but we to test something realRetinoscopy
Really, this is a comment to the question, not an answer to the question. Also it's highly opinionated which is not appropriate for StackOverflow.Cathleencathlene
A
6

Using the AndroidTestCase:getContext() method only gives a stub Context in my experience. For my tests, I'm using an empty activity in my main app and getting the Context via that. Am also extending the test suite class with the ActivityInstrumentationTestCase2 class. Seems to work for me.

public class DatabaseTest extends ActivityInstrumentationTestCase2<EmptyActivity>
    EmptyActivity activity;
    Context mContext = null;
    ...
    @Before
    public void setUp() {
        activity = getActivity();
        mContext = activity;
    }
    ... //tests to follow
}

What does everyone else do?

Axiom answered 20/8, 2012 at 14:27 Comment(0)
T
5

You can derive from MockContext and return for example a MockResources on getResources(), a valid ContentResolver on getContentResolver(), etc. That allows, with some pain, some unit tests.

The alternative is to run for example Robolectric which simulates a whole Android OS. Those would be for system tests: It's a lot slower to run.

Themis answered 4/6, 2015 at 9:22 Comment(0)
O
3

You should use ApplicationTestCase or ServiceTestCase.

Opinionative answered 19/1, 2010 at 21:1 Comment(0)
S
2

Extending AndroidTestCase and calling AndroidTestCase:getContext() has worked fine for me to get Context for and use it with an SQLiteDatabase.

The only niggle is that the database it creates and/or uses will be the same as the one used by the production application so you will probably want to use a different filename for both

eg.

  public static final String    NOTES_DB      = "notestore.db";
  public  static final String   DEBUG_NOTES_DB = "DEBUG_notestore.db";
Shaduf answered 4/5, 2013 at 2:57 Comment(0)
E
1

Initialize context like this in your Test File

private val context = mock(Context::class.java)

Eleneeleni answered 25/5, 2022 at 4:26 Comment(0)
M
0

First Create Test Class under (androidTest).

Now use following code:

public class YourDBTest extends InstrumentationTestCase {

private DBContracts.DatabaseHelper db;
private RenamingDelegatingContext context;

@Override
public void setUp() throws Exception {
    super.setUp();
    context = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_");
    db = new DBContracts.DatabaseHelper(context);
}

@Override
public void tearDown() throws Exception {
    db.close();
    super.tearDown();
}

@Test
public void test1() throws Exception {
    // here is your context
    context = context;
}}
Merozoite answered 12/9, 2016 at 9:30 Comment(1)
“This class was deprecated in API level 24. Use InstrumentationRegistry instead. New tests should be written using the AndroidX Test Library.”Cioffi

© 2022 - 2024 — McMap. All rights reserved.