Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 354
yital9 Avatar asked Aug 10 '15 18:08

yital9


1 Answers

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
            }
        
            ...
        }
        
like image 105
sih4sing5hog5 Avatar answered Oct 03 '22 06:10

sih4sing5hog5