Skip to content

Commit f2d9350

Browse files
authored
Android fragments testing (#36)
* Post: Android Fragments testing * chore: update lines * fix: tags and imports
1 parent fda465e commit f2d9350

File tree

10 files changed

+184
-0
lines changed

10 files changed

+184
-0
lines changed

.idea/.gitignore

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_data/authors.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,8 @@ Dilshan Fernando:
4949
name : "Dilshan Fernando"
5050
avatar : "assets/images/avatars/dilshan_fernando.jpeg"
5151
bio : "Senior QA Engineer - Customer Success"
52+
53+
Raman Koushyk:
54+
name : "Raman Koushyk"
55+
avatar : "assets/images/avatars/raman_koushyk.png"
56+
bio : "Senior QA Engineer - Customer Success"
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
3+
title: "Android Mobile Testing: Fragments"
4+
excerpt: "How to decrease the number of E2E tests and improve coverage with Fragments Testing"
5+
tags: Mobile Android testing
6+
authors:
7+
- Raman Koushyk
8+
header:
9+
teaser: /assets/images/post/espresso-logo.png
10+
teaser_alt: Fragments
11+
category: Software Quality Assurance
12+
13+
---
14+
15+
## **What is Fragment testing on Android**
16+
17+
18+
Firstly, we need to know what Fragments in Android are.
19+
20+
{% include
21+
components/figure.html
22+
url="/assets/images/post/containers.jpeg"
23+
description="Reusable containers"
24+
%}
25+
26+
27+
Fragments are reusable containers within our app allowing us to present the same user interface layout in a variety of activities and layout configurations. Given the versatility of fragments, it's important to validate that they provide a consistent and resource-efficient experience.
28+
29+
Note the following:
30+
* Your fragment shouldn't be dependent on a specific parent activity or another fragment.
31+
* You shouldn't create a fragment's view hierarchy unless the fragment is visible to the user.
32+
33+
To perform Fragments testing we have such helper as AndroidX "fragment-testing" library, which provides the "FragmentScenario" class to create Fragments and change their `Lifecycle.State`. We are able to launch the screen we want to test and skip the rest.
34+
35+
36+
## **Let's Start**
37+
38+
## 0. Before
39+
I'm going to use our test Application to showcase. It's called Jukebox (and was created by our awesome android developer Kunal Jadhav). It's a simple application but ideal for a demo. Let's have a look at it.
40+
41+
{% include
42+
components/figure.html
43+
url="/assets/images/post/E2E_test.gif"
44+
description="E2E Test"
45+
%}
46+
47+
As you can see we have Login, Playing Now, Most Popular and More Menu Screens.
48+
49+
For the demo I want to test Title on Most Popular Screen and check if it contains text according to the requirements or not.
50+
51+
**Before**<br>
52+
In our usual approach(E2E) we would have written a test which would do the following:
53+
- Open the app
54+
- Enter Username and Password
55+
- Click Login button
56+
- Select Most Popular tab
57+
- Check Title
58+
59+
**Now**<br>
60+
Fragments testing approach:
61+
- Open the app at Most Popular Screen in Fragment
62+
- Check Title
63+
64+
What do we need to start using Fragments for testing? The First thing is Dependencies.
65+
66+
## 1. Dependencies
67+
68+
```kotlin
69+
dependencies {
70+
71+
//Fragment testing library
72+
debugImplementation ('androidx.fragment:fragment-testing:1.5.3')
73+
74+
//Espresso and test utilities for local and instrumentation tests
75+
testImplementation ('junit:junit:4.13.2')
76+
debugImplementation ('androidx.test:core:1.4.0')
77+
androidTestImplementation ('androidx.test:runner:1.4.0')
78+
androidTestImplementation ('androidx.test.ext:junit:1.1.3')
79+
androidTestImplementation ('androidx.test.ext:junit-ktx:1.1.2')
80+
androidTestImplementation ('androidx.test:rules:1.4.0')
81+
androidTestImplementation ('androidx.test.espresso:espresso-core:3.1.0')
82+
androidTestImplementation ('androidx.test.espresso:espresso-contrib:3.1.0')
83+
androidTestImplementation ('androidx.test.espresso:espresso-intents:3.1.0')
84+
androidTestImplementation ('androidx.test.ext:junit-ktx:1.1.2')
85+
androidTestImplementation ('androidx.test.uiautomator:uiautomator:2.2.0')
86+
androidTestUtil ('androidx.test:orchestrator:1.4.1')
87+
88+
}
89+
```
90+
NOTE: List of Dependencies(please, be aware of outdated versions)
91+
92+
## 2. Coding
93+
94+
As mentioned earlier, the “fragment-testing” library provides the FragmentScenario class to create fragments. The launchScreen method allows us to launch a fragment which contains a UI. Afterwards, your fragment will be attached to the Activity's root view.
95+
96+
```kotlin
97+
/**
98+
* Launch a screen fragment with the given [fragmentArgs] but its optional.
99+
*/
100+
inline fun <reified S : Fragment> launchScreen(
101+
fragmentArgs: Bundle? = null,
102+
@StyleRes themeResId: Int = R.style.Theme_MyApplication) = launchFragmentInContainer<S>(fragmentArgs)
103+
```
104+
105+
We have launchScreen method, and we can go further. The next stop is our @Before the test part.
106+
107+
```kotlin
108+
@Before
109+
override fun setUp() {
110+
mockedModule = module(override = true) {}
111+
super.setUp()
112+
launchScreen<com.bb.qa_assignment.journey.dashboard.mostPopular.MostPopularScreen>()
113+
mostPopularScreen = MostPopularScreen()
114+
}
115+
```
116+
The first part can be our mocked modules. In some of our projects we use different mocks but its not required for this test project. We can see launchScreen method where we provide the Screen path we want to launch.
117+
118+
```kotlin
119+
@Test
120+
fun testScreenContent() {
121+
mostPopularScreen.apply {
122+
mostPopularTitle.shouldHaveText(R.string.label_most_popular)
123+
}
124+
}
125+
```
126+
In the test we check whether the title is there displaying the text specified in the requirements.
127+
128+
## 3. Results
129+
130+
<figure class="figure d-block text-center mb-4">
131+
<img class="figure-img img-fluid" src="/assets/images/post/fragment_test.gif" style="max-width: 220px">
132+
<figcaption class="figure-caption">Fragment Test</figcaption>
133+
</figure>
134+
135+
Looks pretty nice (if you don't blink) :)
136+
137+
## 4. Metrics
138+
139+
Testing android Fragments in isolation gives us time to d̶r̶i̶n̶k̶ ̶c̶o̶f̶f̶e̶e̶. Seriously, the most important benefits of using such an approach is decreasing execution time and increasing coverage. Let’s compare some results.
140+
141+
I've made the same test but as E2E. You can see the results below.
142+
143+
144+
{% include
145+
components/figure.html
146+
url="/assets/images/post/e2e_fragment_results.png"
147+
%}
148+
149+
The same checks are done using the different approaches. Fragment test is more than 5 times faster, and we avoid possible fails during test execution. Sounds amazing. If we think about the scalability of these tests then the results are even more impressive.
150+
Just imagine that in your project there are 100 E2E tests (execution time of ~20 minutes based on my previous project) and then you replace half of them with Fragment tests. The same checks are performed but your execution time decreases to ~7-8 minutes. You get more stable and less flaky tests.
151+
152+
## 5. Conclusion
153+
154+
I would be really happy if that was the end. Sadly, there are some caveats you must be aware of.
155+
156+
- Testing with Fragments has a close connection with the source code of an app.
157+
You will need to maintain your Fragment tests when some changes in source code occur. It's easier than maintaining E2E but in some cases might get tricky.
158+
- Limitations of testing Real API calls, Some specific logic, Navigation.
159+
You will not able to use Real API calls, all the data should be mocked.
160+
It's not possible to check cases if you need to change your Activity.
161+
It's possible to make a check for navigation but with limitations. It's still better to use E2E tests for that.
162+
163+
164+
## **Final Thoughts**
165+
166+
Introducing Fragments tests won't replace your E2E tests. It should be a mix of E2E and testing with Fragments. That mix gives you the power that your previous automation tool never dreamed of.
167+
168+
The most useful source: https://developer.android.com/guide/fragments/test
169+
170+
Special thanks to: Maria Vlasova
522 KB
Loading

assets/images/post/E2E_test.gif

94 KB
Loading

assets/images/post/containers.jpeg

90.7 KB
Loading
54.4 KB
Loading

assets/images/post/espresso-logo.png

36.2 KB
Loading

assets/images/post/fragment_test.gif

3.82 MB
Loading

0 commit comments

Comments
 (0)