[3] Android Testing - mariamaged/Java-Android-Kotlin GitHub Wiki

Android - Touring the Tests

1. Instrumented Tests

  • Unit tests run much faster, but they cannot test as much, because they do not have access to everything inside of Android.
    • For example, while we could test our ability to talk to a Web service from unit tests, we cannot test our ability to get GPS locations using Android APIs from unit tests.
    • Similarly, most automated UI testing needs instrumented tests, as the Android UI system is only really available to Android.

1.1 What You Can Test

  • However, from a practical standpoint, there will be limits as to what you can test:
    • Emulators do not emulate everything about hardware.
      • For example, you will not be able to test readings that you get from nearby cell towers, as an emulator is not in communication with any actual cell towers.
    • You want your tests to be repeatable.
      • Hence, even on hardware, you may need to limit testing what you really get from the hardware, as you do not control that hardware and what it might return.
      • For example, while in theory you could test getting actual location data via GPS from a device, you cannot guarantee the precise values that will get returned, as GPS is inexact by its nature.
    • Any given device has one set of hardware characteristics.
      • Any given emulator will mimic one set of hardware characteristics.
      • Testing things that vary based on hardware characteristics will require multiple test runs across a fleet of devices or emulators that will reflect the varying characteristics.

1.2 The Test Class

Kotlin

package com.mariamaged.helloworld

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import.org.junit.runner.RunWith

import org.junit.Assert.*

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
	@Test
	fun useAppContext() {
		// Context of the app under test.
		val appContext = InstrumentationRegistry.getInstrumentation().targetContext
		assertEquals("com.mariamaged.helloworld", appContext.packageName)
}
}

Java

package com.mariamged.helloworld

import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWithl;

import static org.junit.Assert.*;

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
	@Test
	void useAppContext() {
		Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
		assertEquals("com.marimaged.helloworld", appContext.getPackageName());
}
}

1.2.1 The Annotations

  • Both Java and Kotlin have a single class, named ExampleInstrumentedTest, annotated with @RunWith(AndroidJUnit::clas) annotation.
    • This annotation tells JUnit - and, more importantly, some Android Studio stuff for running tests - that this class contains test code that should be run as part of an instrumented test.

A Test class can contain one or more of these @Test methods/ functions.

  • When it comes time to run the tests, Android Studio will:'
    1. Create an instance of your test class.
    2. Call one of the @Test methods/ functions on that instance.
    3. Create another instance of your test class.
    4. Call another of the @Test methods/ functions on that new instance.
    5. And so on, until all of the @Test methods/ functions are called.

1.2.2 How You Run Them

enter image description here enter image description here

  • Option 1: you can run/ debug an individual function or method.
  • Option 2: you can run all the test functions/ method by clicking the "double-run button" next to the class name.
Correct Test Results

enter image description here

Failing Test Results

enter image description here

1.2.3 The androidTestImplementation Dependencies

enter image description here

  • The one that is really required is androidx.test:runner.
    • This is the library that supplies the AndroidJUnitRunner class and other core classes for writing and running our instrumented tests.
  • The other one is androidx.test.espresso:espresso-core.
    • This is the core of Espresso, a powerful library for writing GUI tests.

2. Unit Tests

  • They too use JUnit tests.

2.1 Where They Run

  • Unit tests are the same sort of tests that you would run in an ordinary Java or Kotlin project that had no ties at all to building Android apps.

2.2 What You Can Test

  • You can test your non-Android business logic fairly easily, just using standard JUnit tests.
    • However, any code that uses Android-related classes is going to have a problem, though.

You can past this somewhat by the use of mocking engines, such as Mockito.

  • They allow you to create "fake" Android objects based on real Android classes, where you teach the mocks how to respond to particular method calls.

2.3 The Test Class

enter image description here

Kotlin
package com.mariamaged.helloworld

import org.junit.Test
import org.junit.Assert.*

class ExampleUnitTest {
	@Test
	fun addition_isCorrect() {
		assertEquals(2, 2 + 2)
	}
}
Java
package com.mariamaged.helloworld

import org.junit.Test;
import static org.junit.Assert.*;

public class ExampleUnitTest {
	@Test
	void addition_isCorrect() {
		assertEquals(4, 2 + 2);
	}
}

2.2.1 Annotations

  • Unit classes do not normally get a @RunWith annotation.
  • However, we still put @Test annotations on the method or functions that contain the tests to be run.

2.2.2 How You Run Them

enter image description here

  • Option 1: Click the green "run" icon next to a test method/ function to run it alone.
  • **Option 2: Click the "run" icon next to a test class to run all of its test code.

2.2.3 What the Test Result Look Like

enter image description here

2.2.4 The testImplementation Dependencies

  • The one default testImplementation dependency is junit:junit, which pulls in the JUnit classes.