Skip to content

Commit

Permalink
Initial project commit with Android instrumented and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robpridham-bbc committed Jul 16, 2021
1 parent 847b41b commit a819a7c
Show file tree
Hide file tree
Showing 38 changed files with 1,105 additions and 0 deletions.
15 changes: 15 additions & 0 deletions subprojects/androidTest/.gitignore
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
30 changes: 30 additions & 0 deletions subprojects/androidTest/README.md
@@ -0,0 +1,30 @@
# Android Testing Project
## Overview
Unlike the other subprojects, this project is designed to run against the Android toolchain rather than standard Kotlin/Java. This means it should be opened in Android Studio, rather than IntelliJ.

This project was introduced to provide a basic level of assurance for Mockito's correct operation on the Android platform.

This project features the following:
* the minimum app project prerequisites - it is not intended to be run as an actual app
* basic JUnit tests
* basic instrumented tests

While JUnit tests run on the local machine, instrumented tests in the Android context run on a device, which can be an emulator. Due to the Android runtime design, the implementation options for instrumented tests are constrained compared to normal JUnit tests; for example, it is not possible to mock final classes.

## Library Version Definitions / ByteBuddy

Libraries and their versions are defined in `ext.library-versions.gradle`. It is here that you can specify which version of Mockito to test.

ByteBuddy is an optional declaration. If you specify '0' for the ByteBuddy version, e.g.

```bytebuddy_version = '0'```

then ByteBuddy will be as declared by Mockito's own dependencies.

However you are able to specify a _newer_ version if you would like to test an update, and you can do this by specifying a real version, e.g.:

```bytebuddy_version = '1.11.7'```

This will cause ByteBuddy to be directly included in this project using the specified version.

This override is subject to Gradle's dependency resolution process where it reconciles different versions - Mockito's library inclusion vs. the project one. This usually means the newest version is accepted; therefore if you specify a version of ByteBuddy that's _older_ than Mockito's one, it's unlikely to apply it. You would need to use Gradle's `resolutionStrategy` definition to force this.
1 change: 1 addition & 0 deletions subprojects/androidTest/app/.gitignore
@@ -0,0 +1 @@
/build
58 changes: 58 additions & 0 deletions subprojects/androidTest/app/build.gradle
@@ -0,0 +1,58 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
}

android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "org.mockitousage.androidtest"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

dependencies {

implementation rootProject.kotlin_lib
implementation rootProject.core_ktx_lib
implementation rootProject.appcompat_lib
implementation rootProject.material_lib

testImplementation rootProject.junit_lib
testImplementation rootProject.junit_jupiter_api_lib
testImplementation rootProject.junit_jupiter_engine_lib
testImplementation rootProject.mockito_core_lib
testImplementation rootProject.mockito_kotlin_lib
if (rootProject.bytebuddy_version != '0') {
testImplementation rootProject.byte_buddy_lib
}

androidTestImplementation rootProject.android_test_junit_lib
androidTestImplementation rootProject.espresso_lib
androidTestImplementation rootProject.mockito_kotlin_lib
androidTestImplementation rootProject.mockito_android_lib
if (rootProject.bytebuddy_version != '0') {
androidTestImplementation rootProject.byte_buddy_lib
}
}
21 changes: 21 additions & 0 deletions subprojects/androidTest/app/proguard-rules.pro
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,77 @@
package org.mockitousage.androidtest

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify

@RunWith(AndroidJUnit4::class)
class BasicInstrumentedTests {

private var closeable: AutoCloseable? = null

@Mock private lateinit var mockedViaAnnotationBasicOpenClass: BasicOpenClass
@Mock private lateinit var mockedViaAnnotationBasicInterface: BasicInterface

@Before
fun setup() {
closeable = MockitoAnnotations.openMocks(this)
}

@After
@Throws(Exception::class)
fun releaseMocks() {
closeable?.close()
}

//Open class

@Test
fun mockAndUseBasicClassUsingAnnotatedMock() {
val basicClass = BasicOpenClassReceiver(mockedViaAnnotationBasicOpenClass)
basicClass.callDependencyMethod()
}

@Test
fun mockAndUseBasicClassUsingLocalMock() {
val basicOpenClass = mock<BasicOpenClass>()
val basicReceiver = BasicOpenClassReceiver(basicOpenClass)
basicReceiver.callDependencyMethod()
}

@Test
fun mockAndUseBasicClassWithVerify() {
val basicClass = BasicOpenClassReceiver(mockedViaAnnotationBasicOpenClass)
basicClass.callDependencyMethod()
verify(mockedViaAnnotationBasicOpenClass).emptyMethod()
}

//Interface

@Test
fun mockAndUseBasicInterfaceUsingAnnotatedMock() {
val receiver = BasicInterfaceReceiver(mockedViaAnnotationBasicInterface)
receiver.callInterfaceMethod()
verify(mockedViaAnnotationBasicInterface).interfaceMethod()
}

@Test
fun mockAndUseBasicInterfaceUsingLocalMock() {
val basicInterface = mock<BasicInterface>()
val receiver = BasicInterfaceReceiver(basicInterface)
receiver.callInterfaceMethod()
}

@Test
fun mockAndUseBasicInterfaceAndVerify() {
val basicInterface = mock<BasicInterface>()
val receiver = BasicInterfaceReceiver(basicInterface)
receiver.callInterfaceMethod()
verify(basicInterface).interfaceMethod()
}
}
13 changes: 13 additions & 0 deletions subprojects/androidTest/app/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mockitousage.androidtest">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MockitoAndroidTest" />

</manifest>
@@ -0,0 +1,35 @@
package org.mockitousage.androidtest

open class BasicOpenClass {
open fun emptyMethod() {
//do nothing
}
}

class BasicClosedClass {
fun emptyMethod() {
//do nothing
}
}

interface BasicInterface {
fun interfaceMethod()
}

class BasicOpenClassReceiver(private val basicOpenClass: BasicOpenClass) {
fun callDependencyMethod() {
basicOpenClass.emptyMethod()
}
}

class BasicClosedClassReceiver(private val basicClosedClass: BasicClosedClass) {
fun callDependencyMethod() {
basicClosedClass.emptyMethod()
}
}

class BasicInterfaceReceiver(private val basicInterface: BasicInterface) {
fun callInterfaceMethod() {
basicInterface.interfaceMethod()
}
}
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

0 comments on commit a819a7c

Please sign in to comment.