1

Hi guys Im using Robolectric and Mockito and mockito in unit testing, I have come to a point that I need to verify data that depends on a api request call.

How do you code so that your Rest api calls will use mock data when running unit test?

Inside my StockFragment.java, I use SpringAndroid + Robospice to perform a Rest Api call.
Also I have a RequestListener(from Robospice) inside the fragment that updates the UI in the fragment if the request is successful or not.

Here is my fragment:

   public class StockFragment extends RoboDialogFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_layout, container, false);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        displayStockInfo();
    }

    private void displayStockInfo(){
        request = new MyRequest();
        request.setQuote(getStock().getSymbol());
        lastRequestCacheKey = request.createCacheKey();
        ((BaseActivity)getActivity()).getSpiceManager().execute(request, lastRequestCacheKey, DurationInMillis.ALWAYS_EXPIRED, new MyRequestListener());
    }

    private class MyRequestListener implements RequestListener<PseStocksResponse> {
        @Override
        public void onRequestFailure(SpiceException e) {
            //show toast about failure reason ...
        }
        @Override
        public void onRequestSuccess(PseStocksResponse pseStocksResponse) {
            //UPDATE UI VIEWS ...
        }
    }
}

Here is my Robolectric Test class.

   public class StockFragmentTest {
    MyRequest request;
    Stock stock;
    StockFragment stockFragment;

    @Before
    public void setUp(){
        stockFragment = new StockFragment();
        FragmentTestUtil.startFragment(stockInfoFragment);
        FragmentTestUtil.startVisibleFragment(stockInfoFragment);
        findViews();
    }

    public void findViews(){
        quoteTextView = (TextView)stockInfoFragment.getView().findViewById(R.id.quoteTextView);
        nameTextView = (TextView)stockInfoFragment.getView().findViewById(R.id.nameTextView );
        ...
    }

    @Test
    public void viewShouldNotBeNull(){
        assertNotNull(quoteTextView);
        assertNotNull(nameTextView);
        ...
    }

    @Test
    public void showDisplayedInfo(){
        //TODO: Assert textview.getText() values here
    }
}

One solution I am thinking is have testMode flag in the StockFragment and do some conditional statements that will return test data if true, but I think there is a better way to test.
I think I need to listen to Http requests on my Test class and catch that request then provide mock data, Im not sure though.

Note: Robolectric is setup and is confirmed working and tested. Though I did not include them in the code snippet above. Roboguice is also used as injections.

frey
  • 431
  • 1
  • 5
  • 21
  • 2
    I would avoid modifying code to know about test presence – Eugen Martynov Feb 04 '15 at 10:45
  • 1
    This also will fail with `ClassCastException` since `FragmentTestUtil` will try to attach fragment to instance of `Activity` not `BaseActivity` – Eugen Martynov Feb 04 '15 at 10:47
  • But before it will fail with `StubException` because you need to use `RobolectricTestRunner` – Eugen Martynov Feb 04 '15 at 10:48
  • Robolectric is setup properly and does not fail with Stubexception , I just did not include it in the code above. For the ClassCastException, what is your suggested way? – frey Feb 04 '15 at 11:01

2 Answers2

0

I would encourage you to use dependency injection framework like Dagger. It could take a long time to figure out how framework works. Take a look to examples.

I would also encourage you remove network logic from views. Keep it in Activity.

Also (optionally) I would hide notion about usage of specific network framework - RoboSpice.

As for now you could fix test with next steps.

Use Robolectric to run tests:

@RunWith( RobolectricTestRunner.class )
@Config( reportSdk = 18, emulateSdk = 18 )
public class StockFragmentTest {...}

Add mock for SpiceManager:

...
public class StockFragmentTest 
{
    @Mock
    SpiceManager mockedSpiceManager;

    @Before
    public void setUp()
        throws Exception
    {
        MockitoAnnotations.initMocks( this );
        ...
    }
    ...
}

Create test activity:

public class StockFragmentTest 
{
    ...
    public class TestBaseActivity extends BaseActivity 
    {
        @Override
        SpiceManager getSpiceManager() 
        {
            return mockedSpiceManager;
        }
    }
}

Use test activity:

@Before
public void setUp()
{
    ...
    stockFragment = new StockFragment();
    FragmentTestUtil.startVisibleFragment( stockFragment, TestBaseActivity.class, <id of placeholder in xml for BaseActivity> );
    ...
}

I think the last snippet is not applicable for you code. You probably have StockActivity. So you should make TestStockActivity by analogy and replace usage of BaseTestActivity. However I would expect more side effects from this approach. The proper dependency injection will help

Eugen Martynov
  • 19,888
  • 10
  • 61
  • 114
  • Hi Eugene, you're right the ClassCastException happens. I am using Roboguice for injections. Can you give links to resources/articles containing more details or tutorials? The concept is still too broad for me. – frey Feb 04 '15 at 11:22
  • Here is how to use `RoboGuice` with fragments: https://github.com/roboguice/roboguice/wiki/Your-First-Injected-Fragment – Eugen Martynov Feb 04 '15 at 12:47
  • Here is how to do POJO injection: https://github.com/roboguice/roboguice/wiki/Your-First-POJO-Injection – Eugen Martynov Feb 04 '15 at 12:47
  • Here is how to define binding: https://github.com/roboguice/roboguice/wiki/Your-First-Custom-Binding – Eugen Martynov Feb 04 '15 at 12:48
  • Here is how to override injections in test: https://github.com/roboguice/roboguice/blob/master/astroboy/src/test/java/org/roboguice/astroboy/activity/AstroboyMasterConsoleTest.java – Eugen Martynov Feb 04 '15 at 12:49
  • Hi thanks Eugen, Ill definitely take a look on these. – frey Feb 04 '15 at 14:20
0

Robolectric contains already a fake http layer where you can prepare answers.

Details and example can be found in the answers at Android http testing with Robolectric

Community
  • 1
  • 1
nenick
  • 7,340
  • 3
  • 31
  • 23