📜 ⬆️ ⬇️

A systematic approach to testing Android applications, or what the developers were silent

Every tester has an awkward moment sooner or later. A harmful bug has been detected and must be localized. According to the law of meanness, the bug is reproduced unstably, with incomprehensible steps and only on some devices. There are logs, but they are not informative. The developer is engaged in new functionality, he can not distract from the current tasks, until a clear playback steps are found. The manager is waiting for corrections (more quickly, the customer is experiencing).


How to clarify this situation? Nowhere to go, it's time to understand what is happening there "under the hood" of the application.



Of course, you can re-read all the available documentation for developers, but it is unlikely that this time is included in the terms of the project. There is a simpler and more productive way: find out from the developer what the functionality in which the bug occurs.


Understanding the components of the application, you can:



I propose to disassemble some components of the Android system and from the testing side consider the cases that need to be checked for them.


Let's immediately stipulate that the definitions in the article were given by the tester. They do not claim to be the ultimate truth and may contain inaccuracies. Comments and reasoned comments are welcome.


In Android, everything is based on the work of processes. The operating system may terminate the process if it hangs or a new one with a higher priority appears. When the user sees the results of the process, the system takes this process as the highest priority. And if necessary, it will close it last.


In the processes of the work components. Let's start to deal with components such as activations and fragments, and consider cases when the system can stop their work.


Activities and fragments


From the point of view of the tester, activit can be perceived as a screen on which elements are displayed. The application consists of at least one activation. In fact, activit is a container for UI components.


If activit is a container, then fragments are activit UI components. The fragment, in turn, is also a container for UI components.


There is a cool analogy with the browser (thanks to the developers!) For a more visual idea of ​​how activations and fragments are connected with each other. Imagine that we have opened several windows of one browser. This is a few activations within the same application.



Several tabs can be opened inside the window. These are fragments inside the activit.



Fragments work a little faster than activation. But on modern devices, the difference is almost imperceptible. Depending on how the problem is solved, the developer can write the application only for activation or for activation using fragments.


The operating system when managing the life cycle of an application works precisely with the activation of the application. Therefore, while we are most interested in the life cycle of activi.


Users run a large number of applications, which means that many processes are created with activations. Each running process eats the RAM of the device, and it gets smaller. But Android carefully monitors the processes and in case of lack of resources to perform more priority work closes those that are of lower priority.


Let's see at what point the application is “vulnerable” to such system solutions and how this may affect its performance.


Activation Life Cycle


For those who did not know or knew, but forgot.



The activation life cycle is represented by the following states:



Now I will give examples. They cover the main cases that we most often encounter when testing.


First launch of the application



When you first start the application, it creates and loads the main activation in the application.
When switching to the “Resumed” state, the activation is available for user interaction. Everything is great, there are no problems.


Switch from the first screen to the second



Step 1: When switching from the first screen to the second one, the first screen first pauses. At this point, actions such as saving input data and stopping resource-intensive operations (for example, playing animations) can be performed. This happens quite quickly and imperceptibly for the user.


Step 2, 3, 4: Activates the second screen activation.


Step 5: Stops activating the first screen. Also, if the Android at this moment tries to free up memory, the activation of the first screen can additionally go to the “Destroyed” state (i.e., be destroyed).


To better understand what “Paused” is, let’s imagine this situation: the screen above which the alert appeared. We cannot interact with it, but at the same time we see it.


Return from the second screen to the first



When returning from the second screen to the first, almost the same thing happens, only the first activation is not created anew. It is loaded from memory (if, of course, it was not destroyed by the system). The second activation is destroyed after it has been stopped, as it is removed from the transition stack.


Minimize and exit an application



When you minimize the application (for example, by pressing the Home button), the activation stops.
It is important that when you deploy the application, the activity is correctly restored and the data is saved.


On all screens we try to check the minimization-deployment of the application. This case is especially relevant on input forms. Agree, it will be a shame if the text of the letter, which you have so diligently typed, will be erased when the application is minimized. Or the form consisting of multiple fields will become empty again.


When you exit the application (by the hardware button back) in addition to step 1 and step 2, step 3 is performed. Activation is destroyed and the next time you start the application, it is created anew.


Screen rotation



One of the significant cases that breeds bugs - is the rotation of the screen. It turns out that when you turn the screen, the activi goes through a full life cycle. Namely, it is destroyed and re-created. And so at every turn. Therefore, again, we check the rotation on each screen.


Supporting the horizontal orientation of the screen, on the one hand, allows you to verify the correct operation of all activation steps, on the other hand, significantly increases the number of test cases.


Multi mode


Starting with Android 7 (with Android 6 as an experimental feature), a multi-window mode has become available. Users were able to see several applications on the screen simultaneously. However, only the application with which the user is currently interacting is in the “Resumed” state. The rest are set to “Paused”.


Don't keep activities



Do I need to check the full life cycle of activit, if the application does not support screen rotation? Of course, it is necessary.


If the RAM has not been cleaned for a long time, it is not very much, and in parallel with your application some resource-intensive application (for example, PokemonGo) was launched, then the chance that Android will decide to “nail” the process with your activation when switching to another application, is increasing.


How to check the correctness of the application manually, if it does not support screen rotation? Pretty simple: set the checkbox "don't keep activities" in the developer settings and restart the application.


In this case, a situation is emulated when there is not enough memory and Android destroys all activations with which the user does not interact now, leaving only the one that is currently active.


This does not mean that the jackdaw should always be included when testing, but periodically watching the application with the option “don't keep activities” is useful, so that users with weak devices do not suffer and scold us.


Broadcast receiver (broadcast receiver)


To handle external events, the Broadcast receiver component is used. An application can subscribe to system events and other applications. Android delivers an event to a subscriber application, even if it is not running, and thus can “motivate” its launch.


When testing, it is important for us to understand what events are expected and how they are processed.


For example, it was pre-registered in the code that the application waits for a message from a specific number and has access to SMS. When the secret code is received by the user, the Broadcast receiver will receive a notification and an SMS code will be entered in the confirmation field of the operation.


Services


Another very important thing in Android is services. They are needed to perform background tasks. However, the application does not have to be opened by the user at this moment.


Services have several modes of operation. The user can see that the service is running, and maybe completely ignore it.


If you heard the magic word "service" from the developer, do not be lazy, find out what logic of work laid into it:



Here, the main advice in designing test scenarios is to think about user cases, when the work of the service may be interrupted or start to conflict with the work of another service . The most insidious situations: when the work of the service begins, and the user did not expect it. In this case, it is useful to find out what can trigger the launch of the service.


The most simple and innocuous are services without additional parameters . With manual testing, we often do not notice their work. For example, if you need to send data to the analytics system, then it is often for these tasks that such services are used.


Another type of service is sticky services . If the work of such a service is abruptly terminated, then after a while the sticky service will “revive”. It is noteworthy that each time the period before the “revival” increases, so that it interferes less with the work of the system. In some applications, an example of a sticky service might be downloading files to a device. You may have noticed, if you reset the download in the "blind", then after a while it can recover and continue downloading files.


The most important services are those whose work the user "feels" on himself and is important to him. They are called foreground-services , and they always have a notification in the “curtain” that the user cannot close. The system will destroy them last, since the priority of such services is the highest.


For example, a music player. If you minimize the application and even close it, the player continues to play until the user pauses it or closes it. Or until another application or system pauses it. In particular, there can be many options for a music player: an incoming call, another music application, and a sound notification.


Since we are talking about music players, it is worth noting such a thing as audiofocus.


Audiofocus


Imagine that when you run multiple audio players, they will all play at the same time. It is unlikely that someone will like it. Here audiofocus comes to the rescue, which is requested by the application from the system. In the case of a normal request for audiofocus, the system notifies all the running applications: “Now another application will speak, please shut up”. It's funny, but it happens in the format of the request.



If your application is not very polite, then it can safely ignore the request. Our task is to check these situations.


The compromise mode of requesting an audiofocus is called “temporarily intercepting audiofocus . ” This means that the audio focus will return to your application when the interrupting it gives the system a signal that the audio focus has been released.


Another type of audio focus query is “duck” . He asks the rest of the applications not to be silent, but to reduce the volume by half while the sound of the application that requested the focus is playing. For example, such a request is used when playing the sound of a notification about a new message in the messenger.


Testing audiofocus is very important, because here everything is tied to the conscience of the developers and the system does not take a special part in the resolution of conflicts. Well, if the bug still comes out to the users, then do not hesitate, they will quickly inform you about this.


On this, perhaps, while you can finish. Of course, there are many more details and there is no need to take everything into account when testing. In my experience, the tester needs to understand what the application consists of and how it works. This makes it possible to analyze the difficult bugs that arise at the intersection of the business logic of the application and the features of the operating system. Especially when it comes to Android.


PS At the time of writing, we had a dispute. What do you think, what kind of word does the word "Activi" refer to?


')

Source: https://habr.com/ru/post/327416/


All Articles