I am a bit new in testing, so bear with me.
I would like to test the behavior of onDismiss() method of mine. I would like to make sure that onDismiss() calls the showDialog() method for sure. In order to do this, I would like to verify is the mock in showDialog() being called or not.
I am getting an error message, saying there is no interaction with that mock. If I run it with deBug mode, I see we step on the loadingDialog.show() line, still I am getting this error.
Questions:
I would like to know, how can I test a subMethod call in this case?
Why is this happening?
(showDialog() is already covered by separate tests)
test:
sut.onDismiss(mockDialog)
verify(mockLoadingDialog, times(1)).show();
code:
public void onDismiss(DialogInterface dialog) {
showDialog();
}
public synchronized void showDialog() {
loadingDialog.show();
}
Error message: Actually, there were zero interactions with this mock.
package junit;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class BasicTest {
#InjectMocks
private Basic basic;
#Mock
private LoadingDialog mockLoadingDialog;
#Mock
private DialogInterface dialog;
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testOnDismiss() {
basic.onDismiss(dialog);
verify(mockLoadingDialog, times(1)).show();
}
}
Hope this helps!
Using #InjectMocks ensures that the mocks are injected wherever necessary and you do not have to init mocks in setup.
Related
I have changed some imports for Rxjava related to AndroidSchedulers and Observable. when I did that I get the following error.
I am not sure how to proceed with it.
Error
These are my changed imports in my presenter.
import io.reactivex.Flowable;
//import rx.schedulers.Schedulers;
import io.reactivex.schedulers.Schedulers;
//import rx.Observable;
import io.reactivex.Observable;
//import rx.android.schedulers.AndroidSchedulers;
import io.reactivex.android.schedulers.AndroidSchedulers;
Error is on this piece of code as shown in the picture
public void setUserFocusChangeObservable(Observable<Boolean> observable) {
subscriptions.add(observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Boolean>() {
#Override
public void call(Boolean hasFocus) {
//If screen is dimmed, do not allow interaction
if (!screenUtils.isScreenDimmed()) {
if (user != null) {
if (!hasFocus) {
view.renderUserText(user.toString());
}
} else {
//Set text to nothing if interaction happens with autosuggest when screen is dimmed
view.renderUserText("");
}
}
}
}));
}
In the picture I have also highlighted my imports from Gradle
your suggestions are very helpful
R
RxJava 2 changed several class names from RxJava 1. In particular, Action1 has been changed to Consumer:
.subscribe(new Consumer<Boolean>() { /* ... */ })
Make sure you import io.reactivex.functions.Consumer instead of java.util.function.Consumer.
Alternatively, you can use a Java 8 lambda:
.subscribe(hasFocus -> { /* ... */ })
When the parameter to subscribe is fixed, this will also reveal another class name difference: CompositeSubscription is now CompositeDisposable.
I'm trying to do some unit test on a basic Android app. it just do a login to some WS using retrofit my app has a MVP pattern.
What I'm doing?
call to presenter layer this will call to interactor and here I will call to my service
#Override
public void doLogin(String user, String pwd, final LoginListener loginListener) {
try {
final LoginRequest request = new LoginRequest();
request.setEmpleado(user);
request.setPwd(pwd);
Callback<LoginResponse> callback = new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if(response != null && response.isSuccessful() && response.body() != null) {
if("00".equals(response.body().getCodigo())) {
loginListener.authOK();
} else {
loginListener.showError();
}
} else {
loginListener.showError();
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
"+t.getMessage()+" "+t.getCause());
if(t instanceof SocketTimeoutException) {
loginListener.showError();
} else {
loginListener.showError();
}
}
};
WSLogin wsLogin = RetrofitClient.getInstance().getRetrofit().create(WSLogin.class);
wsLogin.autenticar(request).enqueue(callback);
} catch (Exception e) {
loginListener.showError();
e.printStackTrace();
}
My service it's called but i never get into callback
Test
package com.arleckk.loginmvpci.login;
import com.arleckk.loginmvpci.login.presenter.LoginListener;
import com.arleckk.loginmvpci.login.presenter.LoginPresenter;
import com.arleckk.loginmvpci.login.presenter.LoginPresenterImpl;
import com.arleckk.loginmvpci.login.view.LoginView;
import com.arleckk.loginmvpci.model.LoginResponse;
import com.arleckk.loginmvpci.network.WSLogin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
import retrofit2.Call;
import retrofit2.Response;
import static org.junit.Assert.assertEquals;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore("javax.net.ssl.*")
public class LoginTest {
#Mock private LoginView loginView;
#Mock private LoginPresenter loginPresenter;
#Mock private LoginListener loginListener;
#Mock private Call<LoginResponse> loginResponseCall;
Response<LoginResponse> loginResponseResponse;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
loginPresenter = new LoginPresenterImpl(loginView);
}
#Test
public void testOK() throws IOException {
loginPresenter.doLogin("TEST", "TEST1234");
}
}
Another question is: do am I really doing unit test? I mean unit test only test a "Unit" of the code.
I'm expecting a LoginResponse object and then compare it and if it is equals to "00" it's sucessful
No, you're not. For a few reasons. First off, you don't have a test here. You don't have a single assertion. No matter what happens your code will say pass. So it isn't a test. A test would be to say call doLogin with a working login, and ensure that loginListener.authOK() is called. Then another test that uses a bad password, and checks that showError is called. Without that all you have is a waste of time.
Second- this is horribly scoped for a unit test. For a unit test, you should be checking that the smallest unit of code works. Here, you're checking that your entire networking stack, and your server, all work. That's way too much. And a unit test should never depend on an outside server working, that will just lead to a flaky test- something like that should be in an integration suite.
Your code right now isn't optimized for testing. If it was- you wouldn't be creating the retrofit client via a singleton in the code. You'd pass it into doLogin. That way you could pass in a mock in a test that could return a fake response, and then test whether your code can correctly identify the a fake success and failure response correctly, removing the server dependency yet testing all of the functionality.
Say my ContentProvider is called DogProvider. How do I set up my Instrumentation test skeleton? When I try to run the following, I always end up with a null MockContentResolver.
import org.junit.Test;
import org.junit.runner.RunWith;
import android.content.ContentProvider;
import android.database.Cursor;
import android.net.Uri;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.LargeTest;
import android.test.ProviderTestCase2;
import android.support.test.InstrumentationRegistry;
import android.test.mock.MockContentResolver;
import com.bus.proj.data.DogContract;
import com.bus.proj.data.DogProvider;
#RunWith(AndroidJUnit4.class)
#LargeTest
public class ContentProviderTest extends ProviderTestCase2<DogProvider>{
public ContentProviderTest() {
super(DogProvider.class, DogContract.CONTENT_AUTHORITY);
}
#Override
protected void setUp() throws Exception{
setContext(InstrumentationRegistry.getTargetContext());
super.setUp();
}
#Test
public void emptyQuery(){
MockContentResolver contentResolver = getMockContentResolver();
assertNotNull(contentResolver);//fail happens here
Uri uri = DogContract.DogEntry.CONTENT_URI;
Cursor cursor = contentResolver.query(uri,null,null,null,null);
}
}
In your test you're using the AndroidJunit4 test runner, which is based on annotation (compared to the JUnit3 which was based on method names).
This means that your setUp method is probably not called. For it to be called before each test, you need to use the #Before annotation, and make your method public :
#Before
#Override
public void setUp() throws Exception{
setContext(InstrumentationRegistry.getTargetContext());
super.setUp();
}
I have this test class...
package com.blah.blah;
import static org.junit.Assert.assertTrue;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import java.io.IOException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
#Config(emulateSdk = 18)
#RunWith(RobolectricTestRunner.class)
public class IncompatibleClassChangeErrorTest {
private MockWebServer server;
#Before
public void setup() throws IOException {
server = new MockWebServer();
server.play();
}
#After
public void teardown() throws IOException {
server.shutdown(); // TODO Fix if possible. This throws java.lang.IncompatibleClassChangeError
}
#Test
public void test() {
assertTrue(true);
}
}
...and the following exception stack shows up in the consoles of both Eclipse and Android Studio...
Exception in thread "pool-2-thread-1" java.lang.IncompatibleClassChangeError: Class java.net.ServerSocket does not implement the requested interface java.io.Closeable
at com.squareup.okhttp.internal.Util.closeQuietly(Util.java:110)
at com.squareup.okhttp.mockwebserver.MockWebServer$2.run(MockWebServer.java:249)
at com.squareup.okhttp.mockwebserver.MockWebServer$4.run(MockWebServer.java:624)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:695)
...otherwise the test passes. Also running the test from the command line with Gradle just gives a Success message.
If I comment out the server.shutdown(), everything seems OK. Surely this can't be good though?
This seems to be the following issue that was fixed in 1.2.2
https://github.com/square/okhttp/issues/357
If you're using an earlier version, update to latest and see if it still happens.
I have not much experience in unit testing, especially with Mockito and now I have encountered the following situation.
class A {
void setField(String obj) {
}
Object execute() {
throw new RuntimeException("Meh!");
}
}
class B {
//function to be tested
static Object someMethod() {
A a = new A();
a.setField("test");
Object response = a.execute();
//logic here
return response;
}
}
class BTest() {
A aInstance = mock(A.class);
#Test
public void test_someMethod_when_exec_returns_X() {
when(aInstance.execute()).thenReturns("X");// doesn’t work
assertTrue("X", B.someMethod());
}
}
I want to test the someMethod static method when a.execute() returns specific value.
I know, I can create a mock object of A and pass it to someMethod function, which is not a good solution as I should change the signature of someMethod.
What is the correct solution in this case?
If you check out PowerMockito's documentation you'll realize that the following is what you need:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
// execute the test with the appropriate runner
#RunWith(PowerMockRunner.class)
// prepare B for instrumentation so we can hack stuff inside
#PrepareForTest(B.class)
public class MyTest {
#Test
public void bShouldCallA() throws Exception {
// create a mock for A and configure its behaviour
A aMock = mock(A.class);
when(aMock.execute()).thenReturn("X");
// make sure that when A's constructor is called in the static method, the mock above is returned
whenNew(A.class).withNoArguments().thenReturn(aMock);
// do the actual invocation
Object actualResult = B.someMethod();
// check result and interactions
assertEquals("X", actualResult);
verify(aMock).setField("test");
}
}
As I mentioned, the PowerMockito doesn't work in android, you can just mock android object with that. And here comes engineering solution :)
Factory class to create object A.
public class AFactory {
static private AFactory sInsntance = new AFactory();
public static AFactory createObject() {
return sInsntance.createInternally();
}
protected TMMethodBuilder createInternally() {
return new A();
}
//This function is only for testing, in order to inject factory
#Deprecated
public static void setFactory(AFactory mock) {
sInsntance = mock;
}
}
And create object A:
A a = AFactory.createObject();
In Test project extend AFactory and override createInternally() method to return mocked object.
public class AFactoryTest extends AFactory {
private static A a = mock(A.class);
#Override
protected TMMethodBuilder createInternally() {
return a;
}
}
So in test class just do the following:
factory = new AFactoryTest();
a = factory.createInternally();
AFactory.setFactory(factory);
//
when(..).thenReturn();