Robolectric dosen't calling Application.onCreate(), and I cannot get context - android

Hello I have the following project structure
--App
|--SDK1
|--SDK2
In app I have some test for check SDK1 and SDK2.
In SDK I have a singleton pattern only to set the context by the application class that is in App.
And the context is set in the SDK1.singleton in the App.Application.onCreate
The problem is that when I try to execute the following code I always get null:
#RunWith(RobolectricTestRunner.class)
public class CallTest {
#Before
public void setUp() throws Exception {}
#Test
public void connectToSocketTest() {
if (BuildConfig.FLAVOR.equals("dev")) {
Context context = SDK1.getInstance().getContext();
assertNotNull(context);
...
Any idea why this happens, and how can solve it?

That's not the recommended way to get app context in Android using robolectric. You can get your activity by using below code...
Activity activity = Robolectric.setupActivity(MyActivity.class);
To get the app context, just call activity.getApplicationContext().
EDIT1: If you're using the latest Robolectric version, use
Robolectric.buildActivity(DashboardActivity.class) instead.
EDIT2: Make sure your SDK1 extends MultiDexApplication". Add this #Config(manifest=Config.NONE, application = App.class, sdk = 17)` to
the top of your test class.
Let me know if it works.

Related

robolectric throws FragmentManager is already executing transactions

I run a specific unit-test:
#Rule
public ActivityScenarioRule<FragmentUtilActivity> activityScenarioRule2 =
new ActivityScenarioRule<>(FragmentUtilActivity.class);
#Before
public void setUp() {
... //not related to activityScenarioRule2
}
#Test
#Config(qualifiers = "sw600dp")
public void myTest() {
activityScenarioRule2
.getScenario()
.onActivity(
activity ->
standaloneAccountMenuDialogFragment.showNow(
activity.getSupportFragmentManager(), "FragmentTag"));
assertThat(...);
}
I see the #after code is called (with one breakpoint which turned into two breakpoints)
and I get this runtime error:
FragmentManager is already executing transactions
java.lang.IllegalStateException:
at android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManagerImpl.java:1551)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1611)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManagerImpl.java:137)
at android.os.Handler.handleCallback(Handler.java:790)
How can it be if I use activityScenario which is defined once and managed by #Rule annotation? It fails only for this specific test
Any ideas what can it be?
I have seen this issue with Robolectric and ActivityScenario, and it appears to be a race condition where the fragment isn't attached by the time we get to it. There's a warning about this in the default (LEGACY) LooperMode, which is what is used if a mode isn't specified. More details on that in the javadoc here
Try adding #LooperMode(LooperMode.Mode.PAUSED) to the top of your test class, which has some improvements on the Looper behavior. You may also need to add a shadowOf(getMainLooper()).idle() call in the teardown method.
Another workaround, if that doesn't help, is to add sdk=[27] to the config at the top of the test class like this-
#Config(sdk = [27])
There are more details on this issue - https://github.com/robolectric/robolectric/issues/3698

Robolectric and Evernotes android-job library

I'm using Evernotes android-job library for Scheduling jobs and everything works fine but, when i want to run a test case that is running with Robolecteric i get this error :
com.evernote.android.job.JobManagerCreateException: All APIs are disabled, cannot schedule any job
at com.evernote.android.job.JobManager.<init>(JobManager.java:184)
at com.evernote.android.job.JobManager.create(JobManager.java:107)
at com.M.MyApp.MyApplication.onCreate(MyApplication.java:63)
at org.robolectric.android.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:137)
at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:290)
at org.robolectric.internal.SandboxTestRunner$2.evaluate(SandboxTestRunner.java:203)
at org.robolectric.internal.SandboxTestRunner.runChild(SandboxTestRunner.java:109)
basically its pointing to line 63 of my application class :
JobManager.create(getApplicationContext()).addJobCreator(new JobMaker());
Just ran into this same issue after updating the Evernote library to 1.1.11
You can just wrap your initialisation of the JobManager in a try catch and swallow the exception, but a better solution is to create a test version of your application class and load that in for your tests.
The steps are described here.
Move line 63 of your application class to a method - called something like setUpJobManager() - and call that in your onCreate. Then override that method in the test version of your application class.
public class TestApplication extends AppController implements TestLifecycleApplication {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void createJobManager() {
}
Then pass the TestApplication class to your robolectric tests. Just make sure you correctly annotate your Robolectric test classes to use the test application class.
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 23, application = TestApplication.class)

Junit test on Meteor, Android-DDP library

I'm trying to carry out junit test for the Android-DDP library.
To initialize the meteor object, we need a reference to a android context which I'm able to achieve using Robolectric. But the web-sockets is probably talking to the server on a different thread because of which the callback methods are not called and the test methods are getting end.
I used netstat to check if the android client is trying to communicate or not. It shows various ping/pong messages. So, Yes it is trying to talk to the server.
I went through this tutorial as well,
Android AsyncTask testing with Android Test Framework. This one tells how to handle the network on UI thread. But nothing seems right.
The sample code, I have worked is:
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
#RunWith(RobolectricGradleTestRunner.class)
public class MainActivityTest {
private MainActivity activity;
private Meteor meteor;
private String globalUrl = "ws://10.0.3.222:3000/websocket";
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class);
meteor = new Meteor(activity, globalUrl);
meteor.reconnect();
/*
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
}
#Test
public void validateMeteorIsConnected() {
assertTrue(meteor.isConnected());
}
}
Any help would be appreciable. Thanks in advance.
You defined two methods, setup() and validateMeteorIsConnected(), but where are they called?
First, your setup is not correct. After your call to new Meteor(...), you don't need the reconnect() call because the constructor does already establish the connection.
Moreover, you must set up a listener so that you know when the connection has been established or data comes in. This is done with mMeteor.setCallback(...); where the parameter is this or activity.
As you said, the work is done on a different thread and everything is asynchronous.
So you can't just call validateMeteorIsConnected() immediately after connecting.
You need some timer, as shown in the question that you linked to.

having trouble converting from resource to bitmap in an android test

Iam attempting to convert a resource image to a bitmap to test it in an Instrumentation test in android. originally i had this as a regular test extending testcase. my issue is with this
protected void setUp()
{
testbmap=BitmapFactory.decodeResource(getInstrumentation().
getContext().getResources(), R.drawable.ic_launcher);
}
then i test that the bitmap is not null but the test fails.
public void testnotnull()
{
assertNotNull(testbmap);
}
so iam doing something wrong here i think it could b something to do with the first param in the decoderecource(), maybe iam not pointing to the correct resources? I also tried getApplicationContext.getResources() method but iam not too sure on this one.
can anyone help me?
I solved this problem changing #getContext() which will return Context of instrumentation's package to #getTargetContext() which will return context of target application.
Return a Context for the target application being instrumented. Note
that this is often different than the Context of the instrumentation
code, since the instrumentation code often lives is a different
package than that of the application it is running against. See
getContext to retrieve a Context for the instrumentation code.
Kotlin method:
#Test
fun bitmapIsNotNull() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val bitmap = BitmapFactory.decodeResource(context.resources, R.raw.any_image)
Assert.assertNotNull(bitmap)
}

Can you call getInstrumentation() from a test class in a referenced Android library?

I am working on implementing automated unit tests for our application. Want i need to do is be able to choose from a list of test cases and execute said test. My initial idea was to create (1) a standalone application that references a (2) testing library (android project with a bunch of unit tests) that would invoke the activities in our (3) application. So our application of course works fine and I don't want to make any changes there if possible. The standalone application would server as an interface to us developers for executing the tests. I want to be able to add more and more tests to the library. The issue I am having at this point is what follows.
In the library project I have a basic LoginTest activity.
public class LoginTest extends InstrumentationTestCase
{
... other class code
#Override
protected void setUp()
{
solo = new Solo(getInstrumentation());
}
}
My issue is the getInstrumentation() call always returns null. In my library manifest I have
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.matrix.edc.client.android" />
Make sure you have the robotium jar installed. The Solo class belongs to the robotium library.
If you have that installed and I've insulted your intelligence try changing your class declaration to
public class LoginTest extends ActivityInstrumentationTestCase2<YourMainActivity>
and change
solo = new Solo(getInstrumentation, getActivity());
in setUp().
You should also make sure, to call super.setUp() before any attempt of getting the instrumentation. I have not tested every subclass, but for ActivityInstrumentationTestCase2:
#Override
protected void setUp()
{
getInstrumentation(); // returns null
super.setUp()
getInstrumentation(); // returns valid instance
}
trying injecting the instrumentation in your setup, like so
public void setUp() throws Exception
{
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
solo = new Solo(getInstrumentation(), getActivity());
}

Categories

Resources