I am trying to write Unit test cases for Activities in my app by extending the test class with ActivityUnitTestCase. I could successfully run the test cases earlier but now I'm always getting the exception while running them. Even though I'm pretty familiar with handling NullPointerExceptions, I couldn't figure out the problem that's causing this. I couldn't find any similar questions so I'm posting this one.
Stack trace shows me there is a null object reference at this line in my code
activity = startActivity(mIntent, null, null);
But the startActivity method is supposed to get the instance of the activity I'm testing. I'm not sure why it's returning null.
Here is the Stack trace.
java.lang.NullPointerException: Attempt to write to field 'android.os.IBinder android.app.ActivityThread.mLastIntendedActivityToken' on a null object reference
at android.app.Activity.performCreate(Activity.java:6372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:346)
at android.test.ActivityUnitTestCase.startActivity(ActivityUnitTestCase.java:158)
at com.abc.test.MainActivityTest.access$100(MainActivityTest.java:16)
at com.abc.test.MainActivityTest$1.run(MainActivityTest.java:34)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:1891)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Test running failed: Instrumentation run failed due to 'java.lang.NullPointerException'
Here is the Test class
public class MainActivityTest extends ActivityUnitTestCase<MainActivity>{
private Intent mIntent;
private MainActivity activity;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
//Create an intent to launch target Activity as it is not automatically started by Android Instrumentation
mIntent = new Intent(getInstrumentation().getContext(), MainActivity.class);
//Start the activity under test in isolation, in the main thread to avoid assertion error.
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
activity = startActivity(mIntent, null, null);
}
});
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Tests the preconditions of this test fixture.
*/
#SmallTest
public void testPreconditions() {
assertNotNull("MainActivity is null", getActivity());
}
#MediumTest
public void testSecondActivityWasLaunchedWithIntent() {
// Get the intent for the next started activity
final Intent launchIntent = getStartedActivityIntent();
//Verify the intent was not null.
assertNotNull("Intent was null", launchIntent);
//Verify that LaunchActivity was finished
assertTrue(isFinishCalled());
}
}
#prudhvi I don't think I have a silver bullet, unfortunately, but I would suggest trying to follow these steps to upgrade to the new test support libraries in the newer versions of the SDK. Sorry that I can't be of more help!
I had the same issue.
The solution was to make the test an ActivityInstrumentationTestCase2 instead of an ActivityUnitTestCase, and have the activity created for me in the background
There's a good chance something in your application class (i.e. X extends Application) is crashing early on. If that's the case you'll see this error.... Checkout your logcat for traces.
i changed ActivityUnitTestCase to ActivityInstrumentationTestCase2 and removed my startActivity() calls (seems that ActivityInstrumentationTestCase2 automatically starts the activity) now it runs again
Related
I am working on pushing a project into espresso testing currently. I have read a bunch of documents and follow the given practises to get started.
Everything works fine, However, when it comes to Intents related test, the result is strange.
Most of the time, the tests passed in my Mac but fail in my colleague's Windows(not all tests fail) with the the fail message java.lang.IllegalStateException: init() must be called prior to using this method.
Quite strangely, If we Run Debug test in Android Studio flow the code step by step, it passes.
here is the test code:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class MainActivityTest {
#Rule public IntentsTestRule<MainActivity> mRule = new IntentsTestRule<>(MainActivity.class, true, false);
AccountManager accountManager;
MainActivity activity;
private void buildLoginStatus() throws AuthenticatorException {
DanteApp app = (DanteApp) InstrumentationRegistry.getTargetContext().getApplicationContext();
accountManager = app.getDanteAppComponent().accountManager();
DoctorModel doctorModel = AccountMocker.mockDoctorModel();
accountManager.save(doctorModel.doctor);
accountManager.setAccessToken(doctorModel.access_token, false);
}
#Before public void before() throws Exception {
buildLoginStatus();
// must login
assertThat(accountManager.hasAuthenticated(), is(true));
activity = mRule.launchActivity(null);
// block all of the outer intents
intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null));
}
#After public void tearDown() throws Exception {
accountManager.delete();
}
// failed
#Test public void testViewDisplay() throws Exception {
// check tabhost is displayed
onView(withClassName(equalTo(TabHost.class.getName()))).check(matches(isDisplayed()));
// check toolbar is displayed
onView(withClassName(equalTo(ToolBar.class.getName()))).check(matches(isDisplayed()));
}
// passed
#Test public void testCallServiceHotline() throws Exception {
// switch to the account tab layout
onView(withChild(withText(R.string.account))).perform(click());
// click account menu to make a service call
onView(withId(R.id.contact)).perform(click());
// check call start expectly
intended(allOf(
not(isInternal()),
hasAction(Intent.ACTION_DIAL),
hasData(Uri.parse("tel:" + activity.getString(R.string.call_service)))
));
}
// failed
#Test public void testOpenSettingsUI() throws Exception {
// stub all internal intents
Intents.intending(isInternal())
.respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null));
onView(withChild(withText(R.string.account))).perform(click());
onView(withId(R.id.setting)).perform(click());
// check open settings activity successfully
intended(anyOf(
hasComponent(SettingActivity.class.getName())
));
}
}
The testing library version(nearly all dependencies are up to date and we use both physics devices and emulator to test):
rule: 0.4.1
runner: 0.4.1
espresso-*: 2.2.1
support-*: 23.1.0
Any idea deserves an appreciation. Thanks!
Two Solutions:
Use ActivityTestRule instead of IntentsTestRule and then in your #Before and #After manually call Intents.init() and Intents.release() respectively.
Write a custom IntentTestRule and override beforeActivityLaunched() to include your AccountManager logic. Use afterActivityFinished for your current #After logic. This will also allow you to just use the default IntentTestRule constructor. (Preferred Solution)
As to why this is happening:
"Finally on an unrelated note, be careful when using the new IntentsTestRule. It does not initialize, Intents.init(), until after the activity is launched (afterActivityLaunched())." - Shameless plug to my own post (halfway down helpful visual)
I think you are running into a race condition where in your #Before method you are executing launchActivity() then espresso tries to execute intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null)); before your activity is actually created, which means afterActivityLaunched() isn't called, which means neither is Intents.init(), crash!
Hope this helps.
IntentsTestRule is derived from ActivityTestRule and should manage Intents.init() and Intents.release() for you.
However, in my case the IntentsTestRule did not work properly. So I switch back to ActivityTestRule and call Intents.init() before and Intents.release() after the test which sent the Intent.
For more information please see this reference.
What I'm trying to do is implement a unit test, but I need to clear the database before it.
The problem is that sometimes clearing database fails with NullPointerException.
Basicily I call deleteAll method on every DTO I have (for example BusinessUnit.deleteAll(BusinessUnit.class). And sometimes this fail (though not always).
Null pointer originates from SugarRecord's own method:
public static <T extends SugarRecord<?>> void deleteAll(Class<T> type) {
Database db = SugarApp.getSugarContext().getDatabase();
SQLiteDatabase sqLiteDatabase = db.getDB(); // exception is thrown here
sqLiteDatabase.delete(getTableName(type), (String)null, (String[])null);
}
What could have caused this error?
Let the sugarorm start up at first. You have first to let start the SugarOrm. This task needs some time. Therefore add the following:
public class ApplicationTest extends ApplicationTestCase<Application> {
#Override
public void setUp() throws Exception {
super.setUp();
// SugarORM need some time to start up, else tests will fail
Thread.sleep(3000);
}
When i am wrtting
#Before
public void setUp() throws Exception {
Activity activity = Robolectric.buildActivity(ActivityMain.class).create().get();
}
and after running the test Its giving me error org.fest.reflect.exception.ReflectionError: Unable to find method '$$robo$getData' I am using eclipse and ant build for testing the robolectric test for android.
But this code is working fine with my test
#Test
public void testBasicResourceValue() throws Exception {
String helloFromActivity = new ActivityMain().getResources().getString(R.string.str_my_file);
assertThat(helloFromActivity, equalTo("newfile"));
}
so its confirmed that the program is able to get the AndroidManifest.xml
Activity activity =
Robolectric.buildActivity(ActivityMain.class).create().get(); this
line is not working with ANT build i dont know why? i heard
robolectric is stopped supporting ANT.So i found a another workaround
for this problem to get the shadow object of the activity by using
this code given below
#Before
public void setUp() throws Exception {
MyActivity activity = new MyActivity();
//Remember setContentView() has to call before you are trying to get any resource ID from the activity like Button,TextView etc other wise you will get the not shadow object for those views.
activity.setContentView(R.layout.warning);
Assert.assertNotNull(activity);
}
Note: The title of this was changed to better reflect the actual problem.
I've run into a tricky nullPointerException - hoping someone here can give me an idea as to what is going wrong, as I am not successful in recreating the error so that I can get a debug stack trace.
The stack traces in the developer dashboard all indicate that the app is throwing a NullPointerException in onCreate from an Activity subclass (e.g., I have AActivity and BActivity both inheriting from BaseActivity which throws the exception). Presumably this is happening when the app is being resumed after having been thrown out of memory - at least that is my best guess. Although one user reports getting this error immediately on launching the app.
The onCreate function looks as follows:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.camp_ = MyApplication.getInstance().camp();
if (this.camp_ == null) {
this.finish();
return;
}
if (!this.camp_.isSane()) {
this.finish();
return;
}
}
That's essentially it. MyApplication is the Application for the app; getInstance returns a pointer to the instance, or throws an IllegalStateException if the instance is null. isSane() essentially checks whether some of the variables in this.camp_ are null and returns false if the latter is the case.
I can't for the life of me see how this can throw a NullPointerException, but... it apparently does. It's my most frequent cause of error reports at the moment - but I've so far not had any luck provoking the issue myself (a problem I've frequently had with these bugs that only occur when the app restarts after having been wiped from memory).
[Edit 1]
Example stack trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.michael.android.app/com.michael.android.app.gui.GreetActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
at android.app.ActivityThread.access$2300(ActivityThread.java:125)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.michael.android.app.gui.BaseActivity.onCreate(Unknown Source)
at com.michael.android.app.gui.GreetActivity.onCreate(Unknown Source)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
... 11 more
As mentioned BaseActivity is inherited, so there are several variants of this same basic pattern of stack trace. onResume essentially does the same check for validity of the this.camp_ object - there is no onDestroy or onPause code in BaseActivity.
[Edit 2]
The getInstance code looks as follows:
public static MyApplication getInstance() {
checkInstance();
return instance_;
}
private static void checkInstance() {
if (instance_ == null)
throw new IllegalStateException("MyApplication not created yet!");
}
If instance was null, it should be returning an IllegalStateException, not a NPE.
Not really sure this is relevant, but here's a snip of the Application class.
[Edit 3]
public class MyApplication extends Application {
// Instance
private static MyApplication instance_ = null;
private Camp camp_ = null;
public static MyApplication getInstance() {
checkInstance();
return instance_;
}
private static void checkInstance() {
if (instance_ == null)
throw new IllegalStateException("MyApplication not created yet!");
}
// Campaign
public Camp camp() {
return this.camp_;
}
private void parseSettings() {
if (getFileStreamPath("settings.xml").exists()) {
InputStream istream = null;
try {
istream = openFileInput("settings.xml");
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader */
SettingsHandler handler = new SettingsHandler();
xr.setContentHandler(handler);
xr.parse(new InputSource(istream));
} catch (FileNotFoundException e) {
Log.e("MyApplication", "File not found exception: settings.xml");
} catch (Exception e) {
Log.e("MyApplication", "Exception thrown when decoding file settings.xml");
e.printStackTrace();
}
}
}
public void saveSettings() {
// ...
}
#Override
public void onCreate() {
super.onCreate();
// Set the instance
instance_ = this;
BaseActivity.flurryId = flurryId;
parseSettings();
}
public void setCamp(Camp c) {
this.camp_ = c;
}
}
I'm wondering if the issue may be something with the this reference being somehow incorrect in the onCreate methods.
In this code only MyApplication.getInstance() returning null would lead to a NullPointerException. If you want a more detailed explanation please supply the stacktrace and the MyApplication Singleton code.
I am not sure why you are implementing a Singleton pattern on the MyApplication class anyway. Your application is only going to run once, so no need for a Singleton. If you want to access your application instance in an activity you can use
MyApplication application = (MyApplication) getApplication();
Don't you have at least a stacktrace report? You're talking about a NPE but actually not where it is thrown. Sure you present the affected code?
My guess would be that you're relying on some code from previous activities, but since your application is restored the previous activities are not instantiated and the data is null. So I would recommend to search in onDestroy for such data dependent code because it will be called too.
Note that I had a BaseActivity (which is where the NPE occurs), which would be inherited by AActivity and BActivity.
Apparently, the issue was with calling "finish()" in the onCreate of BaseActivity. Moving the finish() calls out of the BaseActivity onCreate calls and instead checking whether to call finish() in AActivity and BActivity fixed the problem.
Hopefully this is of use to someone else. I will change the title to better reflect the actual problem.
I've been trying to make a test case extending intstrumentationtestcase, and whenever I call getinstrumentation() it returns a null instance of Instrumentation instead of an Instrumentation, rendering any of the automation I'm wanting to do useless. I have the permission set in the manifest as well even though I'm only testing the automation on the same app this case is going to run on...any ideas?
You need inject the instrumentation programmatically by calling injectInstrumentation(InstrumentationRegistry.getInstrumentation()); using InstrumentationRegistry from the official Android testing-support-lib:0.1
I had a similar problem and it seems that the getInstrumentation() method returns a valid instrumentation only after the base class (InstrumentationTestCase) setUp method is called. Please look at the code below and check the LogCat debug messages:
import android.app.Instrumentation;
import android.test.InstrumentationTestCase;
import android.util.Log;
public class TestInstrumentation extends InstrumentationTestCase {
private static final String LOG_TAG = BrowseLocationsTest.class.getSimpleName();
private Instrumentation instr;
public TestInstrumentation() {
instr = getInstrumentation();
Log.d(LOG_TAG, "TestInstrumentation instrumentation: " + instr);
}
#Override
protected void setUp() throws Exception {
instr = getInstrumentation();
Log.d(LOG_TAG, "setUp instrumentation: " + instr);
super.setUp();
instr = getInstrumentation();
Log.d(LOG_TAG, "setUp instrumentation: " + instr);
}
public void testInstrumentation() {
Log.d(LOG_TAG, "testInstrumentation instrumentation: " + instr);
}
}
The instrumentation is right in place as expected right after the super.setUp() call.
Had the same problem while using the Testing Support Library with the '#RunWith(AndroidJUnit4.class)' annotation, even though I made sure to inject my instrumentation in the setUp() method as indicated by #Gallal and #Dariusz Gadomski, only it continued to throw NullPointerExceptions.
Turns out, I forgot to include the #Before annotation on my setup method so jUnit4 didn't run it, whereas before with the jUnit3 based Instrumentation tests, it would've run. Since I implemented the instrumentation injection in setUp(), it never got injected even though the code looked like it should have been injecting it.
So instead of
#Override
protected void setUp() throws Exception {
...
Be sure to use
#Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
}
instead.
I think what you really need is Context, in JUnit4, we can get context by InstrumentationRegistry.getContext();