Listener not called in Unit Test - android

I tried to create unit test for my project.
Inside my unit test class I have two methods testCalculate() and testLogin(). Method testCalculate() running fine, meaning that test passed and I got correct testing result.
But problem is in testLogin(), I expect that my code will be print something inside the listener, but it never printed.Meaning that I never get this line
System.out.println("Login success ======= " + response.getResponseObject());
My login method that I want to test itself running fine, meaning if I use it inside my real app, it will login successfully and return some datas that I got from server.
Kindly advise what is possible cause that make my listener is not working in unit test. Really appreciate for any kind help.
#RunWith(RobolectricTestRunner.class)
#Config(manifest = Config.NONE)
public class LoginManagerTest {
private static final String TAG = LoginManagerTest.class.getCanonicalName();
private String usernameStr = "androidtest#gmail.com";
private String passwordStr = "********";
private LoginManager loginManager;
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
}
};
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
}
#Test
public void testCalculate() throws Exception {
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
int num = 5;
int sum = loginManager.calculate(num);
System.out.println("sum = " + sum);
assertEquals(10, sum);
}
}

I had the same issue. I solved by using Robolectric.flushForegroundThreadScheduler(). This will run queued tasks that is on forground thread.
It's going to be like this:
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
}
};
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
ThreadSleep(500); //Wait for login process to be executed
Robolectric.flushForegroundThreadScheduler(); // this will run all the pending queue on Main Thread
}

I think the problem is the callback will be called after time, it means run asynchronus, and the test is out of time with other (main) thread. I have no experience about Robolectric test, but a little bit about AndroidTestSuite. So, I suggest you need some waitting time before the listener callback is called. Here is the sample and the other idea. Hope that help.
Update:
Try the below idea (Not tested):
private Object lock = new Object();
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
synchronized (lock) {
lock.notifyAll(); // Will wake up lock.wait()
}
}
};
synchronized (lock) {
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
lock.wait();
}
}

Related

Nullpointer Exception on return value from a DAO method

I am using a Roomdatabase and I wish to search get a single object from the database when I give it's name. For that I wrote this Query in the DAO :
#Query("SELECT * FROM kuh_table WHERE name = :kuhName ")
Kuh findKuh(String kuhName);
I call it in the repository this way :
public Kuh findKuh(String kuhName){
final Kuh[] kuh = new Kuh[1];
new Thread(new Runnable() {
volatile boolean running = true;
#Override
public void run() {
if(running!= true) {
return;
}
kuh[0] =kuhDAO.findKuh(kuhName);
running = false;
}
}).start();
return kuh[0];
}
then in my ViewModel this way :
public Kuh findKuh(String kuhName){ return repository.findKuh(kuhName);}
I then initialize my ViewModel in a fragment and try using the method by giving a String like this:
MarkerApiKt.setMarkerTapListener(mapView, (MarkerTapListener) (new MarkerTapListener() {
public void onMarkerTap(#NotNull View view, int x, int y) {
Intrinsics.checkNotNullParameter(view, "view");
if (view instanceof MapMarker) {
MarkerCallout callout = new MarkerCallout(context);
callout.setTitle(((MapMarker) view).getName());
callout.setSubTitle("position: " + ((MapMarker) view).getX() + " , " + ((MapMarker) view).getY());
Kuh kuh = kuhViewModel.findKuh(((MapMarker) view).getName());
Toast.makeText(context, "this is "+ kuh.getName(), Toast.LENGTH_SHORT).show();
but somehow the istance of my object is always null since I end up with a nullpointer exception.
Any idea what I may be doing wrong?
So, as #Olli said, the problem was that my thread in my Repository didn't finish its execution, which is why it returned a null object.
I just changed my code this way and now it works fine
public Kuh findKuh(String kuhName) throws InterruptedException {
final Kuh[] kuh = new Kuh[1];
Thread t1 = new Thread(new Runnable() {
volatile boolean running = true;
#Override
public void run() {
if(running!= true) {
return;
}
kuh[0] =kuhDAO.findKuh(kuhName);
running = false;
}
});
t1.start();
t1.join();
return kuh[0];
}

Why toast does not show in asynctask?

I'm beginner in android and trying to show toast in the async task, for that purpose I wrote this code:
public class GetReading {
public GetReading() {
}
public List<ReadingModel> Get(String TokenKey, Context adapter) throws ExecutionException, InterruptedException {
GetReadingTask params = new GetReadingTask(TokenKey, adapter);
List List_result = (List)(new GetReading.AsyncRead()).execute(new GetReadingTask[]{params}).get();
return List_result;
}
private class AsyncRead extends AsyncTask<GetReadingTask, Void, List<ReadingModel>> {
ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List x;
private AsyncRead() {
}
protected List<ReadingModel> doInBackground(GetReadingTask... getReadingTasks) {
final Context pos = getReadingTasks[0].adapter;
Handler handler = new Handler(pos.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(pos, "Created a server socket", 1).show();
}
});
ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading taskService = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading)ServiceGenerator.createService(ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading.class);
Call tasks = taskService.getReadings("application/x-www-form-urlencoded", "application/json", "bearer " + getReadingTasks[0].TokenKey);
try {
this.x = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List)tasks.execute().body();
} catch (IOException var7) {
var7.printStackTrace();
}
return this.x;
}
}
}
and when i try to call that async task with this code:
GetReading reading=new GetReading();
List<ReadingModel> result= reading.Get("VQ",LineActivity.this);
after finishing doinbackground get the toast, but i want to show toast first to user, what happen? how can i solve that problem? thanks all.
Toasts as well as anything that has to do with the UI cannot be fired from any thread that runs in the background.
Move your code for displaying the toast to either onProgressUpdate or on onPostExecute.
All your troubles arise because you use the .get() in
execute(new GetReadingTask[]{params}).get();
Never use .get() as it kills the asynchonity of your task.
Instead: do the things you want to do with the result in onPostExecute().

How to use UnHandledExceptionHandler on android?

recently when I disconnect camera on my device. occur nullpointerException
so , I think use UnhandledExceptionHandler
I try this, first not occur nullpointerException
but app not start.
I want without camera device, app execute well.
MainActivity.class
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String nameOfFrontFacingDevice = VideoCapturerAndroid.getNameOfFrontFacingDevice();
VideoCapturerAndroid capturer = VideoCapturerAndroid.create(nameOfFrontFacingDevice);
if (capturer == null || capturer.equals("") == true) {
Thread.setDefaultUncaughtExceptionHandler(new UnhandledExceptionHandler(this));
throw new NullPointerException();
}
UnhandledExceptionHandler.class
public class UnhandledExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "UnUnHandler";
private final Activity activity;
public UnhandledExceptionHandler(final Activity activity) {
this.activity = activity;
}
public void uncaughtException(Thread unusedThread, final Throwable e) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
String title = "Fatal error: " + getTopLevelCauseMessage(e);
String msg = getRecursiveStackTrace(e);
TextView errorView = new TextView(UnhandledExceptionHandler.this.activity);
errorView.setText(msg);
errorView.setTextSize(2, 8.0F);
ScrollView scrollingContainer = new ScrollView(UnhandledExceptionHandler.this.activity);
scrollingContainer.addView(errorView);
OnClickListener listner = new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
System.exit(1);
}
};
Builder builder = new Builder(UnhandledExceptionHandler.this.activity);
builder.setTitle(title).setView(scrollingContainer).setPositiveButton("Exit", listner).show();
}
});
}
private static String getTopLevelCauseMessage(Throwable t) {
Throwable topLevelCause = t;
while (topLevelCause.getCause() != null) {
topLevelCause = topLevelCause.getCause();
}
return topLevelCause.getMessage();
}
private static String getRecursiveStackTrace(Throwable t) {
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
}
this not showing dialog.
how to use UnhandledExceptionHandler?
Uncaught exception handler is supposed to be used only in the worst case scenario when every other mechanism fails. To handle NullPointerException, you should put that in a try catch block.
I suggest you look into Exception Handling in Java first.
UncaughtException handler- means some unexpected error occured and not allowing the app to crash can lead to unstable results.
Use it only to report or log unexpected exceptions, not as a defense against exceptions. That shows a flaw in the App design.
If you still plan to use UncaughtExceptionHandler, since you are not very aware of how Java works, I suggest you to use another 3rd party service to do this for you..
Eg---> Crashlytics (It has an in built default exception handler and reports crashes when they happen) or ACRA etc....

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();
}
}
});
}});

Trying to update a TextField through a Handler, and getting CalledFromWrongThreadException

I seem to be having trouble with updating a TextView from a thread. I have a GameConnection class (which manages a socket connection) which I want to use across activities. It calls a local "onMessage", which then uses the target handler to call dispatch Message. The "Handler" in this case, is in my GameBrowser activity.
Here's code from the GameConnection class.
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String message = "".intern();
// as a newline character is read, we interpret it as a message
while ((message = in.readLine()) != null && isConnected){
onMessage(message);
}
As said above, a local method "onMessage" method handles dispatching of the message.
private void onMessage(String message){
... // create message from String
handler.dispatchMessage( msg );
}
However, when I get the response in the GameBrowser class, I get a CalledFromWrongThreadException . Initially, I was using a callback method, which of course wasn't working. So, after some research, I've found that I have to use a Handler, but I can't seem to get it right.
public class GameBrowser extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(C.tag, "GameBrowser.onCreate addr:" + this);
handler = new Handler(new HandlerCallback());
connection.addMessageListener(handler);
connection.connect();
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
setContentView(R.layout.game_browser);
}
private class HandlerCallback implements Callback{
#Override
public boolean handleMessage(Message msg) {
if (txtGameLabel == null){
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
}
String message = msg.getData().getString("message");
Log.d(C.tag, "GameBrowser recieved message " + message);
txtGameLabel.setText("Data: " + message);
return true;
}
}
}
I figured out what I was doing wrong. Instead of calling the handler from the socket thread, I used a callback, then used Runnable to post to the handler in the GameConnection class. When onMessage executes "run", which executes "updateTextField", we're back in the main thread.
#Override
public void onMessage(final String message) {
handler.post(new Runnable(){
#Override
public void run() {
updateTextField(message);
}
});
}
private void updateTextField(String message){
if (txtGameLabel == null)
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
txtGameLabel.setText(message);
}

Categories

Resources