I try to mock a method in my instrumentation test but it fails and I am looking for a solution to solve it.
public class MyTest extends InstrumentationTestCase {
private Context mAppCtx;
#Override
public void setUp() throws Exception {
super.setUp();
Context context = mock(Context.class);
mAppCtx = getInstrumentation().getContext().getApplicationContext();
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
}
A crash happens on the following line:
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
And I got following error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
You need to mock each method invocation of: getInstrumentation().getContext().getApplicationContext();
Example:
Instrumentation inst = mock(Instrumentation.class);
Context instContext = mock(Context.class);
ApplicationContext mAppCtx= mock(ApplicationContext.class);
when(getInstrumentation()).thenReturn(inst);
when(inst.getContext()).thenReturn(instContext);
when(instContext.getApplicationContext()).thenReturn(mAppCtx);
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
Related
I'm following MVP architecture in my app using the Nucleus library, and am trying to mock the Presenter for my Fragment. The mock and its overridden invocations work perfectly fine, but my verify calls are strange. First, here's my test:
private User mUser;
private ProfilePresenter mPresenterMock;
#Override
public void setUp() throws Exception {
super.setUp();
mUser = TestUtils.generateTestUser();
mPresenterMock = mock(ProfilePresenter.class);
ProfileFragment fragment = ProfileFragment.newInstance();
fragment.setPresenterFactory(() -> mPresenterMock);
setFragment(fragment);
}
#Test
public void testInitialValues() {
doAnswer(invocation -> {
getFragment().onUserLoaded(mUser);
return null;
}).when(mPresenterMock).loadUser(anyBoolean());
startFragment();
verify(mPresenterMock).loadUser(eq(false));
onView(withId(R.id.empty)).check(matches(not(withEffectiveVisibility(VISIBLE))));
assertEquals(mUser.getFullName(), getFragment().mToolbar.getTitle());
assertEquals(1, getFragment().mVideosRecyclerView.getChildCount());
}
I get a test failure on the verify line:
Argument(s) are different! Wanted:
profilePresenter.start(false);
Actual invocation has different arguments:
profilePresenter.start(1);
What it appears to be doing is verifying a method inside the mocked class, which shouldn't be the case if it's a mocked object. This is the loadUser method inside my Presenter which invokes start:
void loadUser(boolean fresh) {
start(fresh ? USER_FRESH : USER_CACHED);
}
Where start takes an integer parameter.
I've debugged the test and have verified that the Fragment is indeed using the mocked Presenter as expected. I also put a breakpoint inside my doAnswer to verify it is being triggered correctly, and it is.
So what could cause Mockito to verify a method invocation inside of the method I'm trying to verify in the mocked class? I'm using version 1.10.19.
I don't understand why View.getContext() returns null in this case:
#Mock
Context mContext;
#Mock
SensorManager mSensorManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
//...
#Test
public void initWithContext() throws Exception {
assertNotNull(mContext);
assertNotNull(mSensorManager);
when(mContext.getSystemService(Context.SENSOR_SERVICE)).thenReturn(mSensorManager);
ImageView imageView = new ImageView(mContext);
assertNotNull(imageView);
assertNotNull(imageView.getContext()); // Error because getContext() is null
}
First lines of View constructor:
public View(Context context) {
mContext = context;
Method getContext()
#ViewDebug.CapturedViewProperty
public final Context getContext() {
return mContext;
}
I am not mocking the ImageView, why View.getContext() returns null then?
EDIT
when(imageView.getContext()).thenReturn(mContext);
assertNotNull(imageView.getContext()); //Error, imageView.getContext() returns null
If these are pure JVM unit tests (i.e. run on your computer's JVM and not on an Android emulator/device), then you have no real implementations of methods on any Android classes.
You are using a mockable jar which just contains empty classes and methods with "final" removed so you can mock them, but they don't really work like when running normal Android.
See more here: https://developer.android.com/training/testing/unit-testing/local-unit-tests.html#mocking-dependencies
I guess your issue is what #wojtek explained, you're running local unit tests, you can mock something like using the context to retrieve some resource.
If you need to test your views behavior and mocking the Android APIs in the same time, I would suggest trying Robolectric framework
I am trying to test that an API call is scheduled on the right scheduler and observes on the main thread.
#RunWith(PowerMockRunner.class)
#PrepareForTest({Observable.class, AndroidSchedulers.class})
public class ProductsPresenterTest {
private ProductsPresenter presenter;
#Before
public void setUp() throws Exception{
presenter = spy(new ProductsPresenter(mock(SoajsRxRestService.class)));
}
#Test
public void testShouldScheduleApiCall(){
Observable productsObservable = mock(Observable.class);
CatalogSearchInput catalogSearchInput = mock(CatalogSearchInput.class);
when(presenter.soajs.getProducts(catalogSearchInput)).thenReturn(productsObservable);
/* error here*/
when(productsObservable.subscribeOn(Schedulers.io())).thenReturn(productsObservable);
when(productsObservable.observeOn(AndroidSchedulers.mainThread())).thenReturn(productsObservable);
presenter.loadProducts(catalogSearchInput);
//verify if all methods in the chain are called with correct arguments
verify(presenter.soajs).getProducts(catalogSearchInput);
verify(productsObservable).subscribeOn(Schedulers.io());
verify(productsObservable).observeOn(AndroidSchedulers.mainThread());
verify(productsObservable).subscribe(Matchers.<Subscriber<Result<Catalog<SoajsProductPreview>>>>any());
}
}
The line
when(productsObservable.subscribeOn(Schedulers.io())).thenReturn(productsObservable);
throws the following exception, and I don't understand why since productObservable is a mock. Any idea or similar experience?
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
The problem is due Observable::subscribeOn being a final method, which Mockito can't mock.
One possible solution is to use Powermock:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Observable.class)
public class MockTest {
#Test
public void test() {
Observable productsObservable = PowerMockito.mock(Observable.class);
when(productsObservable.subscribeOn(null)).thenReturn(productsObservable);
productsObservable.subscribeOn(null);
verify(productsObservable).subscribeOn(null);
}
}
This is my code:
#Mock
MyApplication application;
#Before
public void setup() {
application = Mockito.mock(MyApplication .class);
}
#Test
public void createProducts() {
application.ormLiteDatabaseHelper.getProductDao().create(new Product());
}
I get a NullPointerException at this line. My Application class inits the OrmLiteDatabaseHelper in its onCreate, how do I access the ormLiteDatabaseHelper from the mocked version of MyApplication?
application is a "mock" object. It only pretents to be a "MyApplication". Thus the only thing it can return for the method ormLiteDatabaseHelper is null and thus calling getProductDao on that will fail with a NullPointerException.
If you want it to return anything, then you need to tell your mock that, for example by...
OrmLiteDatabaseHelper ormLiteDatabaseHelper = ..something...;
Mockito.when( application.ormLiteDatabaseHelper ).thenReturn ( ormLiteDatabaseHelper);
Only then will your mock know to return something else than null. Of course, there are other ways, but for starters... Perhaps you also need partial mocking, which would be explained here, but without further info, it's hard to say.
Also, if you write #Mock, then you should either use the correct #RunWith annotation or call MockitoAnnotations.initMocks(this); instead of creating the mock manually via Mockito.mock. If you want to use the later, you don't need the #Mock annotation.
I'm trying to setup unit tests inside Android Studio (which supposedly is still 'experimental'). How do I get a Context? All the examples I see call AndroidTestCase.getContext() but in my tests this returns null.
public class DummyTest extends AndroidTestCase {
public void testExample() throws Exception {
Context c = getContext();
assertNotNull(c);
}
}
This will result in a AssertionFailedError because the returned context is null.