Reputation: 6702
I have an Activity
public class MyActivity extends ActionBarActivity {
public int i;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
i = getSomeInt();
}
protected int getSomeInt() {
return 1; // here can be an api-request
}
}
and i want to test it with robolectric 3.0
and mockito
.
But i need to mock getSomeInt()
methiod.
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class MyActivityTest {
private MyActivity mActivity;
@Before
public void setUp() {
mActivity = spy(Robolectric.buildActivity(MyActivity.class).create().get());
doReturn(2).when(mActivity).getSomeInt(); //but it is already after onCreate!
}
@Test
public void testGetInt() {
assertEquals(2, mActivity.i); //error
}
}
Is it possible to use already mocked method by creating of activity?
EDIT
i have tried
@Before
public void setUp() {
ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class);
mActivity = spy(co.get());
doReturn(2).when(mActivity).getSomeInt();
co.create();
}
but i seems, that onCreate
was not called by mActivity
assertEquals(2, mActivity.i);
//gives the result:
java.lang.AssertionError:
Expected :2
Actual :0
thanks Eugen for the consideration, it doesnt work, because create
call on controller, that operates with activity that is not spied
Upvotes: 6
Views: 2686
Reputation: 310
Mockito only mocks an object. But it cannot modify the activity reference of ActivityController
.
So I try to isolate the function and pass it to activity before creating.
Four steps:
Isolate the functions as a member of a new class
public class SomeInt{
public int get() {
return 1; // here can be an api-request
}
}
Use the functions by an object in MyActivity
public class MyActivity extends ActionBarActivity {
SomeInt someInt;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
i = someInt.get();
}
}
Make an API to set the object someInt
in test
use ShadowActivity
-- I recommanded this, separating the code and the test
@Implements(MyActivity.class)
public class ShadowMyActivity extends ShadowActivity
{
@RealObject
private MyActivity myActivity;
@Implementation
public void setForMockito(SomeInt someint)
{
myActivity.someint = someint;
}
}
or let the object public
public SomeInt someInt;
or make a public setter for the object in MyActivity
Mock in test
If use ShadowActivity
@Config(constants = BuildConfig.class shadows = ShadowMyActivity.class)
Class TestMyActivity {
@Before
public void setUp()
{
SomeInt someIntMock = mock(SomeInt.class);
ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class);
mActivity.setForMockito(someIntMock);
doReturn(2).when(someIntMock).get();
co.create();
// verify here or in tearDown
}
...
}
Upvotes: 1
Reputation: 5151
I don't think this is possible. I tried to create the Activity in the test, spy it and then create a controller with that spy and I couldn't get that to work so I can't quite imagine how you could do it.
Now that said, it doesn't mean there is no solution to your underlying problem, just that spying the activity is not the way to do it. I would suggest that you ask a second question where you explain specifically what you're trying to achieve (e.g. mock the network component in tests) and you will probably get some alternative solutions that will get you there.
Upvotes: 0