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
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:
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"/>
Should work after this. Best of luck & let me know!
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.