As an android developer, did you ever grew so frustrated with checking the deviceโs Android OS version when using some Android SDK feature that has different implementations between Android versions? ๐ค
How many times you had to write this nifty check?
1
2
3
4
5
6
7
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// do something ๐โโ๏ธ
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// yet do another thing ๐ซฃ
} else {
// Euhh! do this at last ๐ฉ
}
Should we all agree that this is very ugly, repetitve, error prone and mostly not testeable? Well! luckily our job is to make our job easier ๐ค
โป๏ธ Letโs transform this garbage into something useful!
Utilities to help you out โ๏ธ
Weโll define for each android SDK level (that weโre using) a utility function that should return a boolean to pass the check of the SDK level
1
2
3
4
5
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
fun isNougatOrAbove(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.LOLLIPOP)
fun isLollipopOrAbove(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
Now we can rewrite the previous code as the following:
1
2
3
4
5
when {
isNougatOrAbove() -> { // do something ๐โโ๏ธ}
isLollipopOrAbove() -> { // yet do another thing ๐ซฃ }
else -> { // Euhh! do this at last ๐ฉ }
}
โ Done! no need to worry again about the previous ugly syntax, just use the new functions to do the check for you.
Write it, mock it, test it โ> PASS โ
The rule of ๐ in software engineering is DO NOT EVER TRUST YOUR CODE!
If you ask yourself how can I test this code?
1
2
3
4
5
6
7
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// do something ๐โโ๏ธ
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// yet do another thing ๐ซฃ
} else {
// Euhh! do this at last ๐ฉ
}
you will quickly notice that you unfourtunately canโt, well at least not without resorting to Reflection which will definitely make your test FLACKY
and in most cases will fail. Simply because mocking final
properties in not possible with most of mocking frameworks (i.g: mockito
or mockk
).
However, mocking the return of a function is ๐ฏ possible and also recommended ๐. With that in mind testing your code using mockk
becomes as easy as the following:
1
2
3
4
5
6
// prepare the toplevel function for static mocking
mockkStatic(::isNougatOrAbove)
// mock the response
every { isNougatOrAbove() } returns true
// assert the code block is called or some expected results are observed
And there you go! I believe now life is much better ๐ And as always happy coding and may the Source be with you!