DEV Community

Cover image for Unit Testing using Robolectric in Android Studio
Nwokocha wisdom maduabuchi
Nwokocha wisdom maduabuchi

Posted on

Unit Testing using Robolectric in Android Studio

Unit testing is important because it is one of the earliest testing efforts performed on the code and the earlier defects are detected, the easier they are to fix. Early bug-detection is also the most cost-effective for a project, with code fixes becoming more expensive the later they're found in the lifecycle.

Alt Text

What is Unit Testing

UNIT TESTING is a level of software testing where individual units/ components of the software are tested. The purpose is to validate that each unit of the software performs as designed. A unit is the smallest testable part of any software. It usually has one or a few inputs and usually a single output.

Furthermore, Unit tests are the fundamental tests in your app testing strategy. By creating and running unit tests against your code, you can easily verify that the logic of individual units is correct. Running unit tests after every build help you to quickly catch and fix software regressions introduced by code changes to your app.

Two types of automated unit testing in android

Local tests:

Unit tests run on your local machine only. These tests are compiled to run locally on the Java Virtual Machine (JVM) to minimize execution time. If your tests depend on objects in the Android framework, we recommend using Robolectric. For tests that depend on your own dependencies, use mock objects to emulate your dependencies' behavior.

Instrumented tests:

Unit tests run on an Android device or emulator. These tests have access to instrumentation information, such as the Context for the app under test. Use this approach to run unit tests that have complex Android dependencies that require a more robust environment, such as Robolectric.

Benefits of Unit Testing

The goal of unit testing is to segregate each part of the program and test that the individual parts are working correctly. It isolates the smallest piece of testable software from the remainder of the code and determines whether it behaves exactly as you expect.

Unit testing provides numerous benefits including finding software bugs early, facilitating change, simplifying integration, and many others, which we will look right now with more detail.

1. Quality of Code
Unit testing improves the quality of the code. It identifies every defect that may have come up before code is sent further for integration testing. Writing tests before actual coding makes you think harder about the problem. It exposes the edge cases and makes you write better code.

2. Finds Software Bugs Early
Issues are found at an early stage. Since unit testing is carried out by developers who test individual code before integration, issues can be found very early and can be resolved then and there without impacting the other pieces of the code.

3. Facilitates Changes and Simplifies Integration
Unit testing reduces defects in the newly developed features or reduces bugs when changing the existing functionality.

4. Debugging Process
Unit testing helps simplify the debugging process. If a test fails, then only the latest changes made in the code need to be debugged.

5. Design
Writing the test first forces you to think through your design and what it must accomplish before you write the code. This not only keeps you focused; it makes you create better designs. Testing a piece of code forces you to define what that code is responsible for.

6. Reduce Costs
Since the bugs are found early, unit testing helps reduce the cost of bug fixes. Just imagine the cost of a bug found during the later stages of development, like during system testing or during acceptance testing. Of course, bugs detected earlier are easier to fix because bugs detected later are usually the result of many changes, and you don’t really know which one caused the bug.

Running unit test with Robolectric

Robolectric, it is a unit testing framework that allows Android applications to be tested on the JVM without an emulator

Reason to write unit test with Robolectric

1 It provides a way to run our tests inside Android Studio, without launching an app on Device or Emulator.

2 Shadow Classes, rewritten android core libraries by Robolectric, are the real magic of Robolectric. It is a replica of the Android class with some exposed useful functions. Cool, isn’t it?

3 You can test on Android components like:

Activity

Services

Broadcast Receiver

On app resources like:

Localization from strings.xml

Configuration like Landscape or Portrait

Styles and themes

And also for:
Multiple product flavors

How to integrate Robolectric in Android Studio?

Step 1

Add following dependencies in Gradle:

testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:3.2.2'
}



Now, let add UI Button and TextView into our app’s main screen. Following illustrates how our XML codes look like:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.last_step.LastStepActivity">


 <Button
            android:id="@+id/laststepfinishbtn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@drawable/roundedgeeditext"
            android:text="Finish"
            android:textColor="@color/white" />

</android.support.constraint.ConstraintLayout>

The MainActivity class

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


laststepfinishbtn.setOnClickListener {
            val intent =
                Intent(applicationContext, HomeActivity::class.java)

            startActivity(intent)
        }

    }


}


we have to create tests:
There are 3 folders in-app folder > src directory named
androidTest
main
test
We will add all our tests at test > java > [Your Package Name]. It’s standard practice to keep the same project structure of both the main and test folders. It will easy for us to track. Now create MainActivityTest class like this:


@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class MainActivityTest {
    @Test
    fun taketosigninactivity() {
        val activity = Robolectric.setupActivity(LastStepActivity::class.java)
        activity.laststepfinishbtn.performClick()
        val intent = Shadows.shadowOf(activity).peekNextStartedActivity()
        Assert.assertEquals(
            HomeActivity::class.java.canonicalName,
            intent.component!!.className
        )

    }
}



Terms and there meaning:

*assertTrue:
you are asserting that the expression is true. If it is not, then it will display the message and the assertion will fail.

assertTrue("TextView contains incorrect text",
            "Hello world!".equals(tvHelloWorld.getText().toString()));

*assertFalse:
you are asserting that an expression evaluates to false. If it is not, then the message is displayed and the assertion fails.

assertFalse("TextView contains incorrect text",
            "Hello world!".equals(tvHelloWorld.getText().toString()));

*assertNotnull:
you are asserting that the expression is not empty. If it is not, then it will display the message and the assertion will fail.

 assertNotNull("TextView is null", textView);

*shadows:
Shadows are classes that modify or extend the behavior of classes in the Android SDK. Most of the Android core views are built with shadow classes to avoid needing the device or an emulator to run

 val intent = Shadows.shadowOf(activity).peekNextStartedActivity()
        Assert.assertEquals(
            HomeActivity::class.java.canonicalName,
            intent.component!!.className
        )

Useful Link for Asserts methods

all Assert method

Congratulations you have written your first unit test using Robolectric Android library

Top comments (0)