Testing, testing, and testing, these words every developer has heard and created the fear behind that. As a developer most of the time we don’t write a unit test, it may be the reason that it required more time to write and execute those. Somehow I agree with this point, and I am okay if the application works very smooth and scalable.
But if the application does not work smoothly or every time bugs generated then people will complain to the developer for application is not tested properly. It doesn’t matter how much time you invest in design and implementation, but mistakes are inevitable, and bugs will appear in the business logic.
There are many benefits of testing like it gives surety that our application feature working as per implementation and requirement. It also ensures that if we are going to implement any new feature in the application, which will not break my exiting feature etc. Okay, now we got to know there are many more benefits of testing.
As an android developer, we should know what are the testing available to test the feature. Generally, there are two types of testing we can do which are the unit test and instrument test.
Unit Test:
A unit test can be write in app/src/test/java
folder to our project, which runs by java JVM. Generally, it does not require any specific android library. The unit test covers the all business logic which we have written for our application feature. It mostly 70% of our codebase to take care.
Integration/InstrumentationTest:
Integration test can be written inside app/src/androidTest/java
folder. Android system will execute this test, it means to run this test required the android virtual device called emulator or real device. Generally, it can cover 20% of the codebase of our project.
I am not going to cover the unit testing which means the business logic test in this tutorial. We will see the instrumentation test which is based on the android instrument to execute the test cases.
First of all, we need to add few dependencies into the Gradle file to ensure that that can be perform. Here are the few lists.
// Core library implementation 'androidx.test:core:1.2.0' testImplementation "junit:junit:4.13-beta-3" // AndroidJUnitRunner and JUnit Rules implementation 'androidx.test:runner:1.2.0' implementation 'androidx.test:rules:1.2.0' // Assertions androidTestImplementation 'androidx.test.ext:junit:1.1.1' //espresso androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0' // koin implementation 'org.koin:koin-test:1.0.2' // mock implementation 'io.mockk:mockk:1.9.2'
To execute the android instrumentation test file, the system required AndroidTestRunner. I would be recommended to create the custom TestRunner and FakeApplication file which needs to configure with Gradle file.
class FakeRunner : AndroidJUnitRunner() { override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application { return super.newApplication(cl, FakeApplication::class.java.name, context) } }
class FakeApplication : Application() { override fun onCreate() { super.onCreate() } }
defaultConfig { //.... testInstrumentationRunner "com.sunil.arch.common.FakeRunner" }
Okay, now your TestRunner is ready to test the file. Let’s see an example to start testing our room database feature to make sure that working as per our expectation. Now we need to instantiate the Koin module which is required to create the Local database.
private const val DATABASE = "DATABASE" @RunWith(AndroidJUnit4::class) abstract class BaseTest: KoinTest { protected val database: AppDatabase by inject() @Before open fun setUp() { this.configureDi() } @After open fun tearDown() { StandAloneContext.stopKoin() } // CONFIGURATION private fun configureDi() { StandAloneContext.startKoin(listOf(configureLocalModuleTest(ApplicationProvider.getApplicationContext<Context>()))) } private fun configureLocalModuleTest(context: Context) = module { single(DATABASE) { Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) .allowMainThreadQueries() .build() } factory { (get(DATABASE) as AppDatabase).movieDao() } } }
Now my database module is configured with Koin and now we can apply the database testing. I am going to take an example of inserting fake data into our database table and validate to fetch the same data is inserted corrected or not. It this test passed then we can ensure that database inserting and loading feature is working correctly.
class MovieDaoTest : BaseTest() { override fun setUp() { super.setUp() initDataBase() } @Test fun getMovieData() { runBlocking { val movie = database.movieDao().getTopRatedMovies() Assert.assertEquals(1, movie.size) } } private fun initDataBase() { runBlocking { database.movieDao().save(DataSet.FAKE_MOVIE) } } }
Ok, we need to run this test file by AndroidTestRunner to check wether test case is passed or not. We need to run the below command while connected with the android device or android emulator.
gradlew connectedAndroidTest
It will start executing all the text files associated with androidTest folder. The test report will be generated inside your project directory report folder.
Now let’s see the Espresso UI test. Espresso is a testing framework contained in the Android Testing Support Library. It provides APIs to simulate user interactions and write functional UI tests.
Espresso tests are composed of three major components which are:
ViewInteraction.perform()
method.ViewInteraction.check()
method.In this tutorial, let’s see how can check the ViewMatcher component to ensure that the data is inflating on the correct view of our XML. Please disable all the animation of UI from the Gradle file to interact with testing.
testOptions { animationsDisabled = true unitTests.returnDefaultValues = true }
While writing the test classes for espresso we need to understand the few annotations which are commonly used in the android system which are described below:
The first thing to notice here are the annotations:
@RunWith(AndroidJUnit4.class)
: Tags the class as an Android JUnit4 class. Espresso unit test should be written as a JUnit 4 test class.@LargeTest
: Qualifies a test to run in >2s execution time, makes use of all platform resources, including external communications. Other test qualifiers are @SmallTest
and @MediumTest
.@Rule
: ActivityTestRule
and ServiceTestRule
are JUnit rules part of the Android Testing Support Library and they provide more flexibility and reduce the boilerplate code required in tests. These rules provide functional testing of a single activity or service respectively.@Test
: Each functionality to be tested must be annotated with this. The activity under test will be launched before each of the test annotated with @Test
.Ok, let’s create the first espresso test Class to check the data is inflated on the correct view.
@RunWith(AndroidJUnit4::class) @LargeTest class DetailUIUnitTest { private lateinit var detailViewModel: DetailViewModel @get:Rule var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java, true, false) @Before fun beforeTest() { mActivityRule.launchActivity(Intent()) // breakpoint here detailViewModel = mockk() } @After fun afterTest() { } @Test fun test_data_inflating_on_correct_view() { val movie = DataSet.FAKE_MOVIE.first() launchFragment(movie) Espresso.onView(ViewMatchers.withId(R.id.movie_name)).check( ViewAssertions.matches( ViewMatchers.withText( CoreMatchers.containsString(movie.title) ) ) ) }
You can run this file to check whether the test is failed or passed.
09/19 17:04:29: Launching 'DetailUIUnitTest' on samsung SM-J710F. Running tests $ adb shell am instrument -w -r -e debug false -e class 'com.sunil.arch.ui.DetailUIUnitTest' com.sunil.arch.test/com.sunil.arch.common.FakeRunner Waiting for process to come online... Connected to process 22556 on device 'samsung-sm_j710f-52037884fe916345'. Started running tests
Wrapping
Now we have a good understanding of android instrumentation testing. We can play with a few examples of instrumentation testing. You can get the full Github source code of Jetpack Sample. In my next tutorial, we will come with new technical stuff to discuss, ok till then enjoy your healthy day.
If you are wondering to learn Android then Please learn from Android category and wondering to learn Kotlin then Kotlin Category will help you. If you want to learn all the python article, then learn from the python category.
Happy Coding 🙂
I am a very enthusiastic Android developer to build solid Android apps. I have a keen interest in developing for Android and have published apps to the Google Play Store. I always open to learning new technologies. For any help drop us a line anytime at contact@mobologicplus.com
Hi everyone, In this article, we are going to learn how to hide the production… Read More
Hello everyone, Today in this article, we are going to learn about localisation to support… Read More
Hello everyone, In this article, we are going to learn something to handle the callback… Read More
In this article, we are learning about the run time permissions for request permission launchers.… Read More
Hello everyone. In my last tutorial, we learned about the Jetpack Compose introduction and about applying the… Read More
Hello everyone, In this article, we are going to learn about the Jetpack Compose with… Read More