Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 974
Scott LaHay Avatar asked Dec 09 '15 23:12

Scott LaHay


Video Answer


2 Answers

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.

like image 90
Caue Ferreira Avatar answered Oct 06 '22 00:10

Caue Ferreira


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);
    }
}
like image 34
Wilson Wu Avatar answered Oct 06 '22 01:10

Wilson Wu