Roboelectric is giving me a java.lang.IllegalArgumentException: INTERNET permission is required

那年仲夏 提交于 2019-12-12 09:44:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!