Android Testing
How to catch a bug red-handed.
By Nick M, QA Engineer
July 10, 2023
You know that awkward moment, when … Even if you're a qualified QA and can catch a bug with your hands down, sooner or later you encounter a situation where a bug cannot be reproduced steadily.
For example, you catch the bug:
– only using some devices;
– only if you play the same steps for the 5th time;
– only if the developer is watching;
– only when the moon is in its gibbous phase.
How is somebody supposed to work in such conditions?

What if the logs don't help either? The developer is busy with his business, the project manager is waiting for a bug fix. Nowhere to go, you need to understand the work of the application yourself.

You may hardly have time to re-read all available documentation for developers. But you will definitely have time to ask the developer the right question.

This question is: what is the functionality in which the bug arises?
After all, if you, as a tester, can understand how the components of an application function, you can:
1. Build the work of your test cases way better.

2. Find the bugs causes faster.

3. Know what specifically needs to be re-checked after fixing bugs.

4. Confidently discuss emerging issues with developers using previously unfamiliar terms.
Do you agree? Let's figure out the rest.
Do you agree? Let's figure out the rest.
In the Android system, everything is based on the work of certain processes. The operating system may terminate the process if it freezes or a new one with a higher priority appears. When the user sees the results of the process, the system recognizes this process as the highest priority. And if necessary, it will close it last.

Components perform inside the processes. Let's start with components such as activities and fragments, and consider some cases when the system can stop them from performing.
In the Android system, everything is based on the work of certain processes. The operating system may terminate the process if it freezes or a new one with a higher priority appears. When the user sees the results of the process, the system recognizes this process as the highest priority. And if necessary, it will close it last.

Components perform inside the processes. Let's start with components such as activities and fragments, and consider some cases when the system can stop them from performing.
Activities and fragments.
The application consists of at least one activity. Activity functions as a screen on which components are displayed. In fact, an activity is a container for UI components.
If an activity is a container, then fragments are activity UI components. The fragment, in turn, is also a container for UI components.
This connection is best explained by the example of a working browser. Imagine that you have several browser windows opened: in the first window, you surf the reviews on the vacuum cleaner, the next one plays online radio, and in the third one another series of the Game of Thrones stands on pause.

This is a few activities within the same application (pic.1).



Or you open several tabs inside one window because you can't pick a new background for a Facebook page.

These will be еру fragments inside one activity (pic.2).
Fragments are slightly faster than activities. But on modern devices, the difference is almost imperceptible. Depending on how the developing task is solved, the developer can write the whole application using activities only or with activities and fragments.

The operating system when managing the life cycle of an application works precisely with the application activities. Users run a large number of applications, which means that many processes and activities are created. Each operating process grabs the device's RAM, and the memory is running out. But Android monitors the "birth rate" of its processes no worse than the Chinese government, and if there are not enough resources to perform higher priorities, the system closes lower priority processes.

The tester needs to understand at what point the application is "vulnerable" to such system solutions and how this may affect its performance.
Fragments are slightly faster than activities. But on modern devices, the difference is almost imperceptible. Depending on how the developing task is solved, the developer can write the whole application using activities only or with activities and fragments.

The operating system when managing the life cycle of an application works precisely with the application activities. Users run a large number of applications, which means that many processes and activities are created. Each operating process grabs the device's RAM, and the memory is running out. But Android monitors the "birth rate" of its processes no worse than the Chinese government, and if there are not enough resources to perform higher priorities, the system closes lower priority processes.

The tester needs to understand at what point the application is "vulnerable" to such system solutions and how this may affect its performance.
Activity Lifecycle
The activity lifecycle is represented by the following states (pic.3):
Activity Lifecycle
The activity lifecycle is represented by the following states (pic.3):
Here are some examples that illustrate the main cases that we most often encounter when testing.

Test-case #1. Application first launch (pic.4)
When you first start the application, it creates and loads the main activity of the application. When switching to the "Resumed" state, activity is available for user interaction. We see no problem at this point.

Test-case #2. Switching from the first screen to the second (pic.5)
Step 1:
When switching from the first screen to the second one, the previous screen pauses. At this point, actions such as saving entered data and stopping resource-intensive operations can be performed (playing animations for example). This happens quite quickly and stays invisible to the user.

Steps 2, 3, 4:
The second screen activity is started.

Step 5:

The first screen activity is stopped. If Android tries to free up some memory at this moment, the activity of the first screen can enter the "Destroyed" mode.

Test-case #3. Going back to the first screen (pic.6)
When returning from the second screen to the first, almost the same thing happens, except the first activity is not created anew. It is loaded from the memory (if it hasn't been destroyed by the system). The second activity is destroyed after it was stopped, as it is removed from the navigation stack.

Test-case #4. Minimize and exit the application (pic.7)
When you minimize the application (for example, by pressing the Home button), the activity stops. It is very important that when you maximize the application back, the activity is correctly restored and the data is saved.

Please, note:
the process of minimizing and maximizing the application must be checked on each screen. This case is especially useful for the input forms. Simply take the user's side: it is very unpleasant if you typed a letter, then switched the mail app to answer the call, but when you returned, you did not find your text. Also, this should not happen with a data entry form containing a large number of fields. Finding it empty again, the user can go insane. We DO NOT code like that. Period.

When you exit the application (using the hardware "back" button) in addition to step 1 and step 2, step 3 is performed. Activity is destroyed and the next time you start the application, it is recreated.

Test-case #5. Screen rotation (pic.8)
One of the common bug-producing cases is screen rotation. It turns out that when you turn the screen, the activity goes through a full lifecycle. Namely, it is destroyed and re-created at every turn. Therefore, check the rotation on each screen.
Supporting the horizontal orientation of the screen, on the one hand, allows you to check the correct operation of all stages of activity, on the other hand, significantly increases the number of test cases.

Test-case #6. Multi-window mode

Starting with Android 7, 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".

Test-case #7. Do not keep activities (pic.9)

Do I need to check the full activity lifecycle, if the application does not support screen rotation? Sure.

If the RAM has not been cleaned for a long time, and your application is running in parallel with another, more resource-intensive (take at least Google Maps), then the chance that Android decides to "nail down" the process from your activation when switching to another application increases.
How to test the application manually, if it does not support screen rotation?

Please, note:

Simply set the "don't keep activities" checkbox in the developer's settings and restart the application.
How to test the application manually, if it does not support screen rotation?

Please, note:

Simply set the "don't keep activities" checkbox in the developer's settings and restart the application.
In this case, a situation is simulated when there is not enough memory and Android destroys all activities the user does not interact with, leaving only the one that is currently active.

This does not mean that during testing this parameter should always be set, but checking the application with the option "don't keep activities" from time to time is useful. We want satisfied users, right?
In this case, a situation is simulated when there is not enough memory and Android destroys all activities the user does not interact with, leaving only the one that is currently active.

This does not mean that during testing this parameter should always be set, but checking the application with the option "don't keep activities" from time to time is useful. We want satisfied users, right?
Broadcast receiver

To handle external events, the Broadcast receiver component is used. An application can subscribe to the system and other applications events. Android delivers an event to an app-subscriber, even if it is not running, and can also launch it.
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.
Services
Another very important thing in Android is services. They perform background tasks. However, the application does not have to be opened at this moment.

Services have several modes of operation. The user can see that the service is running, or completely ignore it.
Services
Another very important thing in Android is services. They perform background tasks. However, the application does not have to be opened at this moment.

Services have several modes of operation. The user can see that the service is running, or completely ignore it.
If you heard your developer casting another magic "service", try to figure out how this spell works:
  • What does the service do?
  • How does the service behave when the application is not active?
  • Is the service restored after an interruption (incoming call, restarting the phone)?
If you heard your developer casting another magic "service", try to figure out how this spell works:
  • What does the service do?
  • How does the service behave when the application is not active?
  • Is the service restored after an interruption (incoming call, restarting the phone)?
The main advice when designing test scenarios for a given situation: think carefully about the cases in which one service may interrupt or begin to conflict with another service. The most unforeseen situations are as follows: the service began its work, and the user did not expect it. In this case, it is useful to find out what can trigger the service launching.

The simplest services are those that do not have additional parameters. With manual testing, we often do not notice their performance. For example, if you need to send data to the analytics system, then it is often for these tasks that such services are used.
The main advice when designing test scenarios for a given situation: think carefully about the cases in which one service may interrupt or begin to conflict with another service. The most unforeseen situations are as follows: the service began its work, and the user did not expect it. In this case, it is useful to find out what can trigger the service launching.

The simplest services are those that do not have additional parameters. With manual testing, we often do not notice their performance. 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 performance of such a service is abruptly terminated, then after some time the sticky service will "revive". Each time the period before the "revival" increases, so that it interferes less with the work of the system. Sticky service example: downloading files to a device. You may have noticed that if you reset downloading a file in the notification shade, then after a while it can recover and continue downloading files.
The most important services are those whose work the user sees and considers important. They are called foreground-services, and they always have a notification in the notification shade 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 sound notification.
The most important services are those whose work the user sees and considers important. They are called foreground-services, and they always have a notification in the notification shade 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 sound notification.
Let us dwell on this. Sure, there is always a huge amount of details, but you don't need to take everything into account when testing. We believe that 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 application business logic and the features of the Android operating system.

It also makes you a "Lord of testing", doesn't it?
Stay tuned and test like nobody's watching!

We love what we do and do it with pleasure.
QAcamp team

You may also like: