问题
I am retrofitting UnitTests to an existing app. When I run this simple unit test
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import static junit.framework.Assert.assertTrue;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, packageName = "com.blah.blah" )
public class TestThis {
@Test
public void blah(){
assertTrue(true);
}
}
I get this error
java.lang.IllegalArgumentException: INTERNET permission is required.
at com.segment.analytics.Analytics$Builder.<init>(Analytics.java:585)
at com.segment.analytics.Analytics.with(Analytics.java:115)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:140)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:433)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:240)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
java.lang.RuntimeException: java.lang.IllegalArgumentException: INTERNET permission is required.
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:244)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.IllegalArgumentException: INTERNET permission is required.
at com.segment.analytics.Analytics$Builder.<init>(Analytics.java:585)
at com.segment.analytics.Analytics.with(Analytics.java:115)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:140)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:433)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:240)
My first assumption was that robolectric wasn't getting the manifest, but it seems to be there. Is there something fundamental that I'm missing?
Sorry, I was in a hurry when I wrote this and should have added a few more details
I do have this in the manifest
<uses-permission android:name="android.permission.INTERNET" />
I did try explicitly setting the manifest after reading this page Robolectric junit test - missing internet permission
Another update, the problem is an http call triggered in the onCreate()
public class TestApp extends Application {
@Override
public final void onCreate() {
super.onCreate();
singleton = this;
if (!BuildConfig.DEBUG) { Fabric.with(this, new Crashlytics()); }
loadData();
// The next line makes the http call
Analytics.with(getApplicationContext()).identify("userId", null, null);
RequestQueues.initInstance(singleton);
}
}
Any thoughts? I could add
if (notTest)
{
com.segment.analytics.Analytics.with(getApplicationContext()).identify("userId",
}
but would rather not
回答1:
Apparently when running the unit tests using robolectric, the permissions wont be enabled. Checking the Segment lib, it checks for the internet permission as below:
/** Returns true if the application has the given permission. */
public static boolean hasPermission(Context context, String permission) {
return context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
}
But as said, em running the tests your app will not have the internet permission (however you will be able to do internet calls) you can solve that by given the internet permission to a shadow application and then using this context in Segment lib.
Add this method to your TestApp
protected Context instance() {
ShadowApplication shadowApp = Shadows.shadowOf(this);
shadowApp.grantPermissions("android.permission.INTERNET");
return shadowApp.getApplicationContext();
}
And change your code to this
Analytics.with(instance()).identify("userId", null, null);
Hope it help you.
回答2:
I resolved by creating a test application and override the runtime application with it. In this test application, use shadow app to grant permissions. This way you will not touch any actual application to perform test.
public class ShadowTestApp extends TestApp {
@Override
public final void onCreate() {
ShadowApplication shadowApp = Shadows.shadowOf(this);
shadowApp.grantPermissions("android.permission.INTERNET");
Analytics.with(shadowApp.getApplicationContext()).identify("userId", null, null);
}
}
Below is unit test class
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, application = ShadowTestApp.class )
public class TestThis {
@Test
public void blah(){
assertTrue(true);
}
}
回答3:
I tried almost everything mentioned everywhere and nothing worked for me so I came up with this solution. The problem basically is, Roboelectric calls the onCreate()
of the application class when it run the tests and I instantiate the segment SDK in there, hence it was throwing that IllegalArgumentException
and all my tests were failing.
To fix this I removed the initialisation call from onCreate()
of application class and now I am doing lazy initialisation of segment SDK.
Now I initialise the SDK when I need to send the first event and once it is initialised, the singleton instance of Analytics
object is used throughout the app's lifecycle.
This way I didn't have to touch any of your existing test cases and Segment also works fine.
回答4:
I ran into same issue and fixed it as follows -
Initialize the SDK [in my case Segment] that needs INTERNET Permission as a separate function as below -
@VisibleForTesting()
public void initializeSegmentSdk() {
// Create an analytics client with the given context and Segment write key.
Analytics analytics = new Analytics.Builder(this, "xyz")
// Enable this to record certain application events automatically!
.trackApplicationLifecycleEvents()
// Enable this to record screen views automatically!
.recordScreenViews()
.build();
// Set the initialized instance as a globally accessible instance.
Analytics.setSingletonInstance(analytics);
}
Create a Shadow of the class that holds the above method and override this method to return empty.
OR
You can also use Mockito to return nothing whenever initializeSegmentSdk()
method is called
回答5:
Add
<uses-permission android:name="android.permission.INTERNET" />
outside the application tag in your AndroidManifest.xml
来源:https://stackoverflow.com/questions/34190822/roboelectric-is-giving-me-a-java-lang-illegalargumentexception-internet-permiss