Viktor Matskevich

Asynchronous tasks in the application and Android Instrumentation Test.

Currently, almost all applications have asynchronous tasks. A striking example of it — requests to the server.

Let's consider the following case. We will upgrade our calculator from the last article. Let's suppose the situation where we can get the result of calculation after running the inquiry by clicking on "Calculate" button. For it there is necessary to remake handler of "Calculate" button pressing.

We'll turn calculate() method of class in AsyncTask:
AsyncTask used to simulate the usual request to the server.

Then a new test to check the calculate() function is writing.
And run our test again.
Test is failed. Why? The picture below clearly shows what went wrong:
It should to recall that the calculate() method is now called in the doInBackground() method of AsyncTask class. This method is not called in the main flow and getInstrumentation ().waitForIdleSync() tool waits until the queue at the base stream will stand not empty. In consequence of that, there is a problem in that the check of the results occurs earlier than all the streams are synchronized. It is certainly is not satisfied us.

There is a necessary to carry out an artificial synchronization for correct test passing.

It can be done in the following ways:
  • getInstrumentation().waitForIdleSync()
  • Synchronized
There was a discussion about this feature in the last article. Briefly reminding — it waits until all UI threads will complete their work. So how we can apply it if the created thread is not the UI thread?

It is simple. It need to add an animated object, where the animation will be completed after the calculate() function fulfilment. The most obvious option is to add to our layout ProgressBar.

Let's a bit reconstruct the structure of the markup. The new layout is presented:
And also a bit of modernizing our code just like that.

Then we make the re-test. Excellent, test is passed!
You can see the following situation. When we mapped the progress bar, its animation turned on. All activities related to the submission, are the UI thread. That's why the function getInstrumentation().waitForIdleSync() is pending.

But this method has a huge minus. Sometimes it is necessary to remove the animation on the DUT to test. If we turn off the animation, there will be not an expectation. That is why we consider now the second case related to thread synchronization.
The essence of the method consists in the fact that we create an object and, using synchronized design (Object) {}, stop the test until our object will not cause notif() function. It will call this function when the callback method will goes off.

It is necessary to implement the following steps for this method realization:

1) To write interface for feedback.

2) To create an instance of this interface in the test and pass its Activiti, redefine it, and set the reference to its methods.

3) Add a synchronization point to the test.

Let's start with writing interface. It will look as follows:
The idea is the calculateIsDone() method will be called after the calculation.

We declare in class a variable mMainActivityCallBack, it is an instance of interface, and create a setter for this variable:
But that's not all. We still need to add a call calculateIsDone() method. To do this, it need to go to the calculate() method and appends the following after the calculation of:
Now let's turn to class. It need to add the following code before calling calculateButton.performClick() function:
Here, we simply create an object for synchronization and changed callback for Activity.

In the overridden method, we will synchronize the object syncObject by calling notify() function.

It is also necessary to add the following fragment after calling calculateButton.performClick() method:
This is our synchronization point. The wait() method waits until notify ()method will carry out. More details on this process can be seen at the picture.
After it we run our test and see that it passed.
That’s the simple way we have managed to solve the problem of asynchronous tasks.

As a general rule, the addition methods for tests in the main class — is not good. Usually there is create a helper class, and all the extra features are appends there. Because it shouldn’t to mix the main methods for the application and tests together. It should distinguish the functional. It will be discussed in the next article as the final part.
Thanks for reading!