Home Better Android Backward Compatibility Checks ๐Ÿ‘
Post
Cancel

Better Android Backward Compatibility Checks ๐Ÿ‘

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!

This post is licensed under CC BY 4.0 by the author.