Process crashes during creation of RoboGuice injector, if there is a mocked instance in any module

后端 未结 2 1227
我寻月下人不归
我寻月下人不归 2021-02-01 11:32

I have a problem with using RoboGuice and AndroidMock frameworks in unit testing. I\'ve created a simple project to show my problem. Here I create a mocked instance and register

相关标签:
2条回答
  • 2021-02-01 12:27

    Unfortunately, if there's an issue with the setup steps for RoboGuice & unit testing, you can get this sort of error. No magic short answer, but rather a set of steps to follow exactly.

    BTW, you're using RoboGuice 1.1 - AbstractAndroidModule & RoboUnitTest no longer exist in RoboGuice 2.0. RoboGuice 1.1 is deprecated, so best overall solution is to move to newest version according to these instructions Upgrading to 2.0.

    However, just in case you're attached to RoboGuice 1.1, here's some steps to follow:

    • Don't have inconsistent generated code/build files after refactoring/changing package names etc. Delete generated code, do a Clean & Build, even recreate a new project and copy source files in.
    • Have your app code in one project (RoboGuice dependent, Instrumentation/RoboUnitTestCase/AndroidMock independent). You app code project has within lib: guice-2.0-no_aop.jar and roboguice-1.1.2.jar.
    • Have your unit test code in another project that references it (RoboGuice independent, Instrumentation/RoboUnitTestCase/AndroidMock independent). Instructions here Before You Get Started. Your test code project has within lib: AndroidMockGenerator.jar.
    • In your app project, your App + Module classes look something like this:

      package com.mypackage;
      
      import android.app.Instrumentation;
      import android.content.Context;
      
      public class MyApplication extends roboguice.application.RoboApplication {
      
      static MyModule myModule;    
      
      // this constructor usually called by app
      public MyApplication(Context context) {
          super();
          attachBaseContext(context);
      }
      // This constructor called by unit tests.  This is unfortunately small amount of 
      // 'abstraction leakage' of unit test needs into app code.
      public MyApplication(Instrumentation instrumentation) {
          super();
          attachBaseContext(instrumentation.getContext());
      }    
      public static void setModule(MyModule module) {
          MyApplication.myModule = module;
      }   
      public static MyModule getModule() {
          return MyApplication.myModule;
      }   
      }
      

      And

      package com.mypackage;
      
      public class MyModule extends roboguice.config.AbstractAndroidModule {
      // this will be injected
      protected UsefulObject myUsefulInstance;    
      
      public void setUsefulObject(UsefulObject usefulInstance) {
          this.myUsefulInstance = usefulInstance;
      }    
      public UsefulObject getUsefulObject() {
          return this.myUsefulInstance;
      }    
      
      @Override
      protected void configure() {
          bind(UsefulObject.class).toInstance(myUsefulInstance);
      }
      

      }

    • In your test project, your test case class looks something like this:

      import android.test.suitebuilder.annotation.LargeTest;    
      import com.mypackage.MyApplication;    
      import com.mypackage.MyModule;    
      import com.mypackage.UsefulObject;    
       //import com.mypackage.UsefulObjectSimpleImplementation;    
      import android.test.suitebuilder.annotation.MediumTest;    
      import android.test.suitebuilder.annotation.SmallTest;    
      import com.google.android.testing.mocking.AndroidMock;    
      import roboguice.test.RoboUnitTestCase;
      
      public class TestMyModule extends RoboUnitTestCase<MyApplication> {
      
      @Override
      protected void setUp() throws Exception {
          UsefulObject instance = // new UsefulObjectSimpleImplementation(); 
                                  AndroidMock.createNiceMock(UsefulObject.class);           
          MyModule mockModule = new MyModule();
          mockModule.setUsefulObject(instance);
          MyApplication.setModule(mockModule);
          super.setUp();
      }
      
      // Make sure you use one of the @*Test annotations AND begin
      // your testcase's name with "test"
      @MediumTest
      public void test01() {
          AndroidMock.expect(MyApplication.getModule().getUsefulObject().
               simpleMethod()).andStubReturn("Hello!");
      }
      

      }

    • Ensure that for the test project, the AndroidManifest.xml file has the following entry:

       <instrumentation android:name="android.test.InstrumentationTestRunner"
         android:targetPackage="com.mypackage"
         android:label="Tests for com.mypackage"/>
    
    • Before running your test, ensure your emulator is started and is running healthily, by running a different, simple "Hello World" app first. When this succeeds, then run your app. Lastly, run your test project.

    Should work after this. Best of luck & let me know!

    0 讨论(0)
  • 2021-02-01 12:29

    Unfortunately this is a bug in Android itself. See the bug report here. The VM crashes when it tries to look for annotations on a Proxy, which is what AndroidMock uses when mocking an interface.

    The workaround is to create in instance of a class that implements the interface, as you pointed out in your question. You could try making a pure abstract class that implements the interface without implementing any methods, then use AndroidMock to mock that class instead of the interface. This should avoid the creation of a Proxy.

    0 讨论(0)
提交回复
热议问题