How to verify void method with the Mockito - android

I'm writing some unitTest for a class that its name is NetworkRequest.
In this class, I have a function that its name is run.
public void run(NetworkResponseListener listener) {
if (listener == null)
return;
this.mListener = listener;
CheckInternetAccess.checkInternetAccess(manager, new NetworkStateListener() {
#Override
public void onInternetResponse(int internetCode) {
if (internetCode == ErrorCodes.CODE_HAS_INTERNET_ACCESS) {
runRequest();
} else {
mListener.onNetworkResponse(null);
}
}
});
}
I want to create a test when the input listener(NetworkResponseListener)
be null.
I wrote something like below:
public class NetworkRequestTest {
private ReceivedRequest receivedRequest = Mockito.mock(ReceivedRequest.class);
private ConnectivityManager connectivityManager = Mockito.mock(ConnectivityManager.class);
private NetworkStateListener networkStateListener = Mockito.mock(NetworkStateListener.class);
#Test
public void checkInternetAccessShouldNotCallWithNullListener() {
NetworkRequest networkRequest = new NetworkRequest(receivedRequest, connectivityManager);//SUT
networkRequest.run(null);
Mockito.verify(CheckInternetAccess.checkInternetAccess(connectivityManager, networkStateListener), Mockito.never());
}
}
I want to check verification of CheckInternetAccess.checkInternetAccess
But I got an error that says:
Wrong 1st argument type. Found: 'void', required: 'java.lang.Void'

Try using Mockito.verifyZeroInteractions(...) on your mock objects.

Related

How to clear static method status during junit test

The test function test_init_1() succeed, but test_init_2() fails
That is because MyService has been already initialized.
#RunWith(RobolectricTestRunner::class)
class TrackingServiceInitTest {
#Test
fun test_init_1() {
val result = MyService.init(context, id1)
assertTrue(result) // result = `true`
}
#Test
fun test_init_2() {
val result = MyService.init(context, id2)
assertTrue(result) // AlreadyInitialized Exception has thrown!
}
#After
fun tearDown() {
// what should I do here to clear MyService's state?
}
}
MyService looks like:
public class MyService {
public static synchronized boolean init(Context context) {
if (sharedInstance != null) {
Log.d(TAG, "Already initialized!");
throw new AlreadyInitialized();
}
// initializing..
sharedInstance = new CoreService();
return true
}
}
How can I clear such status?
The right solution would be adding a static method to MyService marked with #VisibleForTesting which releases sharedInstance:
public class MyService {
public static synchronized boolean init(Context context) {
if (sharedInstance != null) {
Log.d(TAG, "Already initialized!");
throw new AlreadyInitialized();
}
// initializing..
sharedInstance = new CoreService();
return true;
}
#VisibleForTesting
public static void destroy() {
sharedInstance = null;
}
}
And then in your tearDown you can call MyService.destroy().

How can I wait for an object filled asynchronously in Android UI thread without blocking it?

I have a singleton to handle the registration and elimination of an entity Profilo ( a Profile).
This entity is set by passing an identifier and gathering information on the server in an async way.
My problem is that when I have to return my instance of profilo if it's not still loaded it will return null.
public class AccountHandler {
private static AccountHandler istanza = null;
Context context;
private boolean logged;
private Profilo profilo;
private AccountHandler(Context context) {
this.context = context;
//initialization
//setting logged properly
assignField(this.getName());
}
}
public static AccountHandler getAccountHandler(Context context) {
if (istanza == null) {
synchronized (AccountHandler.class) {
if (istanza == null) {
istanza = new AccountHandler(context);
}
}
}
return istanza;
}
public void setAccount(String nickname, String accessingCode) {
logged = true;
assignField(nickname);
}
//other methods
private void assignField(String nickname) {
ProfiloClient profiloClient = new ProfiloClient();
profiloClient.addParam(Profilo.FIELDS[0], nickname);
profiloClient.get(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode,
Header[] headers,
JSONArray response) {
JSONObject objson = null;
try {
objson = (JSONObject) response.getJSONObject(0);
} catch (JSONException e) {
e.printStackTrace();
}
AccountHandler accountHandler = AccountHandler.getAccountHandler(context);
// Profilo is created with a JSONObject
// **setProfilo is called in async**
**accountHandler.setProfilo(new Profilo(objson));**
}
});
}
private void setProfilo(Profilo profilo) {
this.profilo = profilo;
}
public Profilo getProfilo() {
if( logged && profilo == null)
//How can I wait that profilo is loaded by the JsonHttpResponseHandler before to return it
return this.profilo;
}
}
Instead of calling getProfilo you could use a callback mechanism in which the AccountHandler class notifies the caller when the profile has been loaded. e.g.
public void setAccount(String nickname, String accessingCode, MyCallback cb) {
assignField(nickname, cb);
}
private void assignField(String nickname, MyCallback cb) {
....
accountHandler.setProfilo(new Profilo(objson));
cb.onSuccess(this.profilo);
}
Create an inner Interface MyCallback (rename it) in your AccountHandler class
public class AccountHandler {
public interface MyCallback {
void onSuccess(Profilo profile);
}
}
Now whenever you call setAccount you will pass the callback and get notified when the profile is available e.g.
accountHandler.setAccount("Test", "Test", new AccountHandler.MyCallback() {
void onSuccess(Profilio profile) {
// do something with the profile
}
}
I added, as #Murat K. suggested, an interface to my Class that will provide a method to be call with the object when it is ready to be used.
public class AccountHandler {
public interface Callback {
void profiloReady(Profilo profilo);
}
}
This method is called in getProfilo in a Handler that makes recursive calls to getProfilo until profilo is ready to be used, then it call the callback method which class is passed as argument of getProfilo.
public void getProfilo(final Callback Callback) {
if( logged && (profilo == null || !profilo.isReady() ) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getProfilo(Callback);
}
}, 500);
}else
Callback.profiloReady(profilo);
}
Example of getProfilo call
public class ProfiloCall implements AccountHandler.MyCallback {
#Override
public void profiloReady(Profilo profilo) {
//Use profilo as needed
//EXECUTED ONLY WHEN PROFILO IS READY
}
public void callerMethod() {
//useful code
accountHandler.getProfilo(this);
//other useful code
}
}

Can't create handler inside thread that has not called Looper.prepare(), while implementing IdlingResource

I’m attempting to write Espresso unit test that depends on a component that makes TCP/IP network connection to an external app in order to pass successfully.
The test failed to due the fact that the TCP/IP network took longer than the allowed by Espresso...
Therefore, we need to have TCP/IP code Class TCPConnectionTask implement IdlingResource:
However, I'm getting, this exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.app.Activity.<init>(Activity.java:786)
at com.sample.QuicksetSampleActivity.<init>(QuicksetSampleActivity.java:82)
at com.unitTests.QuicksetSampleActivityTest.<init>(QuicksetSampleActivityTest.java:52)
I enclosed the TCPConnectionTask and called Looper.prepare() & also attempted Looper.prepareMainLooper() , with no success, see below (TCPConnectionTask):
/**
* Async task to connect to create TCPIPDataComm and connect to external IRB.
*
*/
public class TCPConnectionTask extends AsyncTask<String, Void, Void > implements IdlingResource {
String ip_user = null;
int port_user;
private ResourceCallback callback;
private boolean flag = false;
protected Void doInBackground(String... args) {
try {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable() {
#Override
public void run() {
Looper.prepare();
//Looper.prepareMainLooper();
flag = true;
TCPIPDataComm tcp = new TCPIPDataComm(ip_user, port_user);
if(tcp != null){
tcp.open();
_TCPDataComm = tcp;
// we can enable the DataComm interface for simulation in UI app
int resultCode = 0;
try {
resultCode = QuicksetSampleApplication.getSetup().setDataCommInfo(
getAuthKey(), _TCPDataComm.getHostName(),
_TCPDataComm.getPortNumber());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
//task completed
flag = false;
}
Log.d(QuicksetSampleActivity.LOGTAG,
"Setting DataComm Result = "
+ resultCode
+ " - "
+ ResultCode
.getString(resultCode));
}
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setInfo(String ipValue, int portNumber)
{
ip_user = ipValue;
port_user = portNumber;
}
#Override
public String getName() {
return this.getClass().getName().toString();
}
#Override public boolean isIdleNow() {
if (flag && callback != null) {
callback.onTransitionToIdle();
}
return flag;
}
#Override public void registerIdleTransitionCallback(ResourceCallback callback) {
this.callback = callback;
}
}
Below is the relevant snippet of the unit test class, QuicksetSampleActivityTest:
#RunWith(AndroidJUnit4.class)
public class QuicksetSampleActivityTest extends ActivityInstrumentationTestCase2<QuicksetSampleActivity> {
private QuicksetSampleActivity newQuicksetSampleActivity = null;
private final String ip = "192.168.43.139";
private final int port = 9999;
private final int timeOutTime = 1000;
//This is the idling resource that takes time to complete due to network latency...
private QuicksetSampleActivity.TCPConnectionTask taskIdlingResource = null;
//const
public QuicksetSampleActivityTest() {
super(QuicksetSampleActivity.class);
//instantiation of idling resource that is used for TCP connection
taskIdlingResource = new QuicksetSampleActivity().new TCPConnectionTask();
}
#Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
//open activity
newQuicksetSampleActivity = getActivity();
// Make sure Espresso does not time out
IdlingPolicies.setMasterPolicyTimeout(timeOutTime * 10, TimeUnit.MILLISECONDS);
IdlingPolicies.setIdlingResourceTimeout(timeOutTime * 10, TimeUnit.MILLISECONDS);
//register idling resource
Espresso.registerIdlingResources(taskIdlingResource);
}
#After
public void unregisterIntentServiceIdlingResource() {
//unregister idling resource
Espresso.unregisterIdlingResources(taskIdlingResource);
}
//The EditText GUI with the port & Ip was noe found using espresso, we need to set teh ip & port programmatically
public void setIpandPortToPcBridge() {
// Use TCPCommunicatuonTask interface
taskIdlingResource.setInfo(ip, port);
taskIdlingResource.execute();
}
//after TCP connection is made and/or tested
#Test
public void testActionBarMenuItemsIrDevicesAfterTCPConnectionFunctions() {
//we were not able to find the IP & Port fields so set them programmatically
setIpandPortToPcBridge();
//open action bar menu
Espresso.openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
//test IR Devices/Functions menu item
Espresso.onData(Matchers.allOf(Matchers.instanceOf(MenuItem.class), MatcherUtility.menuItemWithTitle("IR Devices/Functions"))).perform(ViewActions.click());
//add new device will connect the app
Espresso.onView(ViewMatchers.withId(R.id.btAdd)).perform(ViewActions.click());
//DeviceFunctionsActivity is rendered
Espresso.onView(ViewMatchers.withText("IR Devices")).check(ViewAssertions.matches(ViewMatchers.withText("IR Devices")));
//find the 3 required buttons for this UI
//test START learning
//Espresso.onView(ViewMatchers.withText("Start")).check(ViewAssertions.matches(ViewMatchers.withText("Start")));
//click
//test CANCEL learning
//test TEST Learned IR
//Espresso.onView(ViewMatchers.withText("Test Learned IR")).check(ViewAssertions.matches(ViewMatchers.withText("Test Learned IR")));
//click
//test Delete Learn Code
// Espresso.onView(ViewMatchers.withText("Delete Learn Code")).check(ViewAssertions.matches(ViewMatchers.withText("Delete Learn Code")));
//click
//go back
//ViewActions.pressBack();
}
}
}
How can I resolve this exception, and run the Espresso IdlingResource successfully?
Try
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
// Your testActionBarMenuItemsIrDevicesAfterTCPConnectionFunctions() test body
}
});
Example of usage with ActivityTestRule:
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
mMusicPlayerActivityTestRule.getActivity()
.getSupportMediaController().registerCallback(
new MediaControllerCompat.Callback() {
#Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state);
if (state.getState() == STATE_PLAYING) {
countDownLatch.countDown();
}
}
});
}});

How to test asyc retrofit calls in Android unit tests?

I am struggling to write unit tests for my API implementation in Android. I would like to test the Retrofit functionality but run into concurrency problems, where I do not know how to ensure that the async API calls get executed and finish before I start testing the Android internal database calls.
Here is my test function:
public class postPrintModeTest extends ActivityInstrumentationTestCase2<MainActivity> implements IConstants {
public MainActivity activity;
public postPrintModeTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
activity = getActivity();
String printModeName = "LSD Mode";
int parentId = 4;
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("name", printModeName);
payload.put("parentId", parentId);
APIExec.getInstance().postPrintMode(IConstants.authorization, IConstants.userId, IConstants.deviceUid, payload); // <- this needs to finish before I execute the tests, so I have proper data in the database.
}
#SmallTest
public void testPrintModeCreated() {
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
assertNotNull("Print Mode does not exist", printMode);
}
#SmallTest
public void testPrintModeName() {
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
if(printMode != null)
{
assertTrue("Print Mode name is not correct", printMode.getName().equals("LSD Mode"));
}
}
}
and here is the async method in question:
public void postPrintMode(String authorization, final int userid, String deviceuid, final Map payload){
api.postPrintMode(authorization, userid, deviceuid, payload, new Callback<PrintMode>() {
#Override
public void success(PrintMode printMode, Response response) {
if (printMode.get_id() != 0) {
dbOps.writePrintMode(userid, printMode);
bus.getBus().post(new EVTNewPrintMode(printMode));
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
APIUtils.showAPIResponseBody(retrofitError);
}
});
}

NPE when getting Robolectric ShadowApplication with Volley and Dagger

In my Android application I have set up Volley.
Robolectric.application is initialized and all other tests runs smoothly.
I get this error when trying to get mocked HTTP response.
This is my test:
#RunWith(MyRobolectricTestRunner.class)
public class ApiTests {
#Inject
protected Api api;
#Before
public void setUp() {
ObjectGraph.create(new AndroidModule(Robolectric.application), new TestApplicationModule()).inject(this);
}
#Test
public void shouldGetErrorList() throws Exception {
Project project = new Project("test", "test", "test", DateTime.now());
addPendingProjectsErrorsResponse("response.json"); //adding response to FakeHttpLayer
api.getProjectErrors(project, new Listener<ProjectErrors>() {
#Override
public void onResponse(ProjectErrors response) {
assertNotNull(response);
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
throw new RuntimeException(error);
}
}
);
}
}
This is error I get:
Exception in thread "Thread-3" java.lang.NullPointerException
at org.robolectric.shadows.ShadowLooper.getMainLooper(ShadowLooper.java:59)
at android.os.Looper.getMainLooper(Looper.java)
at org.robolectric.Robolectric.getUiThreadScheduler(Robolectric.java:1301)
at org.robolectric.shadows.ShadowSystemClock.now(ShadowSystemClock.java:15)
at org.robolectric.shadows.ShadowSystemClock.uptimeMillis(ShadowSystemClock.java:25)
at org.robolectric.shadows.ShadowSystemClock.elapsedRealtime(ShadowSystemClock.java:30)
at android.os.SystemClock.elapsedRealtime(SystemClock.java)
at com.android.volley.VolleyLog$MarkerLog.add(VolleyLog.java:114)
at com.android.volley.Request.addMarker(Request.java:174)
at com.android.volley.CacheDispatcher.run(CacheDispatcher.java:92)
I had same error and avoid it by using my own (and ugly) SystemClock shadow.
shadow class:
#Implements(value = SystemClock.class, callThroughByDefault = true)
public static class MyShadowSystemClock {
public static long elapsedRealtime() {
return 0;
}
}
test code:
#Test
#Config(shadows = { MyShadowSystemClock.class, ... })
public void myTest() {
}
Another workaround would be to disable Volley logging by calling
VolleyLog.DEBUG = false;
in your setUp method.

Categories

Resources