yital9
yital9

Reputation: 6702

How to mock method before activity is created?

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

Answers (2)

sih4sing5hog5
sih4sing5hog5

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:

  1. Isolate the functions as a member of a new class

    public class SomeInt{
        public int get() {
            return 1; // here can be an api-request
        }
    }
    
  2. 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();
        }
    }
    
    1. 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

    2. 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

Alex Florescu
Alex Florescu

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

Related Questions