Skip to content

Commit cacb994

Browse files
authored
Merge pull request #1 from guhungry/add-code-coverage-to-androidTest
chore: Add code coverage to android test
2 parents be72898 + f2099c5 commit cacb994

File tree

18 files changed

+330
-86
lines changed

18 files changed

+330
-86
lines changed

.travis.yml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,25 @@ jdk:
1212
# as per http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
1313
sudo: false
1414

15-
before_install:
16-
# Install SDK license so Android Gradle plugin can install deps.
17-
- mkdir "$ANDROID_HOME/licenses" || true
18-
- echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license"
19-
- echo "d56f5187479451eabf01fb78af6dfcb131a6481e" >> "$ANDROID_HOME/licenses/android-sdk-license"
20-
- yes | sdkmanager "platforms;android-18"
15+
licenses:
16+
- 'android-sdk-preview-license-.+'
17+
- 'android-sdk-license-.+'
18+
- 'google-gdk-license-.+'
19+
20+
install:
21+
- echo 'count=0' > /home/travis/.android/repositories.cfg # Avoid harmless sdkmanager warning
22+
- echo y | sdkmanager "platform-tools" >/dev/null
23+
- echo y | sdkmanager "tools" >/dev/null # A second time per Travis docs, gets latest versions
24+
- echo y | sdkmanager "build-tools;28.0.3" >/dev/null # Implicit gradle dependency - gradle drives changes
25+
- echo y | sdkmanager "platforms;android-26" >/dev/null # We need the API of the emulator we will run
26+
- echo y | sdkmanager "platforms;android-28" >/dev/null # We need the API of the current compileSdkVersion from gradle.properties
27+
- echo y | sdkmanager --channel=4 "emulator" >/dev/null # Use canary channel to get emulator 29.x for x86_64 image support
28+
- echo y | sdkmanager "extras;android;m2repository" >/dev/null
29+
- echo y | sdkmanager "system-images;android-26;default;x86_64" >/dev/null # install our emulator
30+
- echo no | avdmanager create avd --force -n test -k "system-images;android-26;default;x86_64" -c 10M
31+
- emulator -verbose -avd test -no-accel -no-snapshot -no-window $AUDIO -camera-back none -camera-front none -selinux permissive -qemu -m 2048 &
32+
- android-wait-for-emulator
33+
- adb shell input keyevent 82 &
2134

2235
# script for build and release via Travis to Bintray
2336
script: gradle/buildViaTravis.sh
@@ -33,9 +46,16 @@ cache:
3346
directories:
3447
- $HOME/.m2
3548
- $HOME/.gradle
49+
# Android SDK
50+
- /usr/local/android-sdk
3651

3752
env:
3853
global:
54+
- ANDROID_HOME=/usr/local/android-sdk
55+
- ANDROID_SDK_ROOT=/usr/local/android-sdk
56+
- TOOLS=${ANDROID_HOME}/tools
57+
- PATH=${ANDROID_HOME}:${ANDROID_HOME}/emulator:${TOOLS}:${TOOLS}/bin:${ANDROID_HOME}/platform-tools:${PATH}
58+
- QEMU_AUDIO_DRV=none
3959
- secure: oUlPXht69hzfb3N9eMdw39P6KYNrMM2YIXcZlsvBRowQNxtE3TTkGEP3DIbBCxpJyokWc7zazmMAy19Z2TngPpDDeaR8f1hBG6R/J/O4ZOCpfWoR5U4wB8qTnc0HBy8atqMWq5dzLhP4N1vsOXtyJ/JBJwMkDMytm6j2QYrDxyLZKA7A/6jEFI5BtFVqenwHQC1T0bpYLC9aaOgannnAKffKpYY2WVhqj4X72iuuf8eRQQBCTzKmhhqluJOWwRPJL7IuUIzkcIIHyGUUz+KsN05vYL9DOR1NokWP+oEFMHw5XavW7h0DM5iKVW4JMqVJm1bSpxkC3Dngxo9IbnWVk4xn5G80gDlviaMy8ukUMwxF846yd4dskbjV2t/wdec9G4NNUlX7a9HlSfBJ9sAW8WOd1sn9z2HbOKgwt5wkkTWzKGMU0dKhmN6WElrzuLUNsof/NW8d3NhM9MSB3vkn4avFOERbjMpx5kayW/HQA19iwq/vh2f5olIidME//iCzfu6qRu4OmMH50kO797Gn6qKMZmf68wxUxOqeLTj+LnF7Y3ERaGMFbZ0qu4F5PsO6Yt6mx8m52n+e1qrdX7BqtpGgexQEvuc6nQJGmAPIezCYepK18/six6F/QstykEJpAKee/F2RIkd7wfGBHIFFXxbvXluYW537GFuFuEZRYlw=
4060
- secure: ehd0VTpDn0ehomVYewJn1TiMa1aMhfZ2oRnNnxMNS1GjCBRkKTne++wbe91iPp4TeD/e7WcdFJRKZlW8oFk/bPoJZeyru1uIj1lBa7hmhA706wcrnFyLAeJt2Uzko3ZTzQm2ERaSek4UbXhDqaYIWxDoAuOntIXyF4ojU++PSkubV+T9X/HPBgCd6BE8nC4XXhIdLbwdTvatRrPezgcAQy9yAQnAlAbSaoyjYln2bRsf8fup97hBaUM0TtQuQ8uOWq/4fxQBzreqHsxxkiOA1EbogCAY4ZruauBorjkdU5qokI4SYKry7L1paaxQlM6DHsZuQI3kMuqN8kmZsYbQM/ryMpICXa6OswCiCnVrd7pQ1qouRolpXJmNiOHBe10j1LqnzkfFoz85dTou5/boHa5GVYCQM+sNhsbEpa3yMCQ2rSpPr86xCj14bgZAs+MZ6YArB1ZK/1wKjyUVOyEddStgamiXLEe3rdq3+00o9aiGDVaa6uq9cdm6doh0AP460b4zx1+ocZH5A3PSiOO+DTSn1sZasqOrUvJgzJcCLL7o5Y7BVP4d6Vk2YtbukOBNgB6mh2rCeh1mro7rhy9iwBX6BUN9CwxPyxNPwu0+KwWFQ+UsbJD4FatWnScXlWkTeXrK3M/PUAno+jrD5fydMtv1V0dbTdW70PXZNtEnVdE=
4161
- secure: OZqwl85WUApFhGe9LxeSH+Fkb0rimfK6dMxHtF5flhGZvBkupQjXTaAbs/KGaFeKk/QxQIfmAkuufx3qLITpzzJKWmXUTiWKBJoGcW8qX482qVOKrAK7FG7QlDER6ie3PahOvg1Pyn4H2DedoGHaky02tnUuAIw4hG9HfjeMr+KJ9fcaSz+LPD/IJFFJz9WhqOausdp//xVnUM4Y6ZVS41I19ifhL57QKY0MVoI4a/Wrjh9FAL44bFnPPlUE0WBIv7SMWDYC8Pg+FuyNRA8nuclWv/U0jU6qAf9IePlrhdwJj0LeM//TKGgGJs/XhyWDMns6ejOZC1XDRTtKpLoevAzOOFEe4NbjSXtSp1vbx4Z7bkYAcn6S9uFEeu36qCoU7r1ezCtkUpNx1n3K6efCXChbv7GdlG/bDi6QlaFA4VjERG1Lnqknr/80wBhHlu/ICarg/Cw5P0drWjxh9R2aQ/dGHbnP42Iw7lgMkaVo3pwmfm1b2pnZcMseRHHE4rkbcgzGiQpG0Vf1OapkL4DXC+5UqbpQEpLJZhxe9rKOSOtXKUSXVZXYdc697HQHe2zG1bOL28ZAP7xtEnMb/MgQeDZmM5SFUT6zz3gSwiSKE2pr60PAQH+IDykBUBQIoNjLMiDUd89IqLgB7WsRLplBG3chVuhqatS6NnVp3Fa4txI=

build.gradle

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.3.41'
4+
ext.kotlin_version = '1.3.50'
55
ext.mockito_version = '2.25.1'
6-
ext.spekVersion = '1.2.1'
76
ext.androidJunit5Version = '1.4.2.1'
87
ext.junitJupiterVersion = "5.4.2"
98
ext.junitVintageVersion = "5.4.2"
@@ -16,9 +15,6 @@ buildscript {
1615
dependencies {
1716
classpath 'com.android.tools.build:gradle:3.5.0'
1817
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
19-
classpath "org.junit.platform:junit-platform-gradle-plugin:1.2.0"
20-
classpath "de.mannodermaus.gradle.plugins:android-junit5:$androidJunit5Version"
21-
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
2218
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
2319
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
2420
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2'

photomanipulator/build.gradle

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
apply plugin: 'com.android.library'
22
apply plugin: 'kotlin-android'
33
apply plugin: 'kotlin-android-extensions'
4-
apply plugin: 'de.mannodermaus.android-junit5'
5-
apply plugin: 'jacoco-android'
64
apply plugin: 'com.github.dcendents.android-maven'
75
apply plugin: 'com.jfrog.bintray'
86

@@ -16,7 +14,6 @@ android {
1614
versionName "1.0.1"
1715

1816
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19-
testInstrumentationRunnerArgument "runnerBuilder", "de.mannodermaus.junit5.AndroidJUnit5Builder"
2017
}
2118

2219
compileOptions {
@@ -40,12 +37,10 @@ android {
4037
}
4138

4239
testOptions {
43-
junitPlatform {
44-
filters {
45-
engines {
46-
include 'spek'
47-
}
48-
}
40+
animationsDisabled true
41+
42+
unitTests {
43+
includeAndroidResources true
4944
}
5045
}
5146
}
@@ -57,35 +52,19 @@ dependencies {
5752

5853
implementation 'androidx.appcompat:appcompat:1.1.0'
5954

60-
// (Required) Writing and executing Unit Tests on the JUnit Platform
61-
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
62-
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
63-
64-
// (Optional) If you need "Parameterized Tests"
65-
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion"
55+
testImplementation 'org.hamcrest:hamcrest:2.1'
56+
testImplementation 'org.hamcrest:hamcrest-library:2.1'
6657

67-
// (Optional) If you also have JUnit 4-based tests
6858
testImplementation 'junit:junit:4.12'
69-
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:$junitVintageVersion"
7059
androidTestImplementation 'androidx.test:runner:1.2.0'
7160
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
7261
androidTestImplementation 'androidx.test:core:1.2.0'
7362
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
7463

75-
// Tests - Spek
76-
testImplementation("org.jetbrains.spek:spek-api:$spekVersion") {
77-
exclude group: "org.jetbrains.kotlin"
78-
}
79-
testImplementation("org.jetbrains.spek:spek-junit-platform-engine:$spekVersion") {
80-
exclude group: "org.junit.platform"
81-
exclude group: "org.jetbrains.kotlin"
82-
}
8364
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
8465
// Mockito
8566
testImplementation "org.mockito:mockito-core:$mockito_version"
8667
androidTestImplementation "org.mockito:mockito-android:$mockito_version"
87-
88-
testImplementation 'org.hamcrest:hamcrest-library:2.1'
8968
}
9069
repositories {
9170
mavenCentral()
@@ -115,6 +94,7 @@ ext {
11594
allLicenses = ["MIT"]
11695
}
11796

97+
apply from: "${project.projectDir}/jacoco.gradle"
11898
apply from: "$rootDir/gradle/jcenter.gradle"
11999

120100
if (project.hasProperty('bintrayUser') && project.hasProperty('bintrayKey')) {

photomanipulator/jacoco.gradle

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apply plugin: 'jacoco'
2+
3+
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
4+
reports {
5+
xml.enabled true
6+
html.enabled true
7+
}
8+
9+
def fileFilter = ['**/R.class', '**.R$.class', '**/BuildConfig.*', '**/Manifest*.*', '**/Test*.*', 'android/**/*.*']
10+
def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter)
11+
def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter)
12+
def mainSrc = "${project.projectDir}/src/main/java"
13+
14+
sourceDirectories = files([mainSrc])
15+
classDirectories = files([debugTree, kotlinDebugTree])
16+
executionData = fileTree(dir: "$buildDir", includes: [
17+
"jacoco/*.exec",
18+
"outputs/code_coverage/**/*coverage.ec"
19+
])
20+
}

photomanipulator/src/androidTest/java/com/guhungry/photomanipulator/BitmapUtilsAndroidTest.kt

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import android.graphics.BitmapFactory
55
import android.graphics.ColorSpace
66
import android.graphics.PointF
77
import android.util.DisplayMetrics
8+
import androidx.annotation.DrawableRes
89
import androidx.test.ext.junit.runners.AndroidJUnit4
9-
import androidx.test.platform.app.InstrumentationRegistry
1010
import com.guhungry.photomanipulator.test.R
1111
import org.hamcrest.MatcherAssert.assertThat
1212
import org.hamcrest.Matchers.equalTo
@@ -16,31 +16,77 @@ import org.junit.runner.RunWith
1616

1717
@RunWith(AndroidJUnit4::class)
1818
internal class BitmapUtilsAndroidTest {
19-
var background: Bitmap? = null
20-
var overlay: Bitmap? = null
19+
private var background: Bitmap? = null
20+
private var overlay: Bitmap? = null
21+
private var output: Bitmap? = null
2122

2223
@After
2324
fun tearDown() {
2425
background?.recycle()
2526
background = null
2627
overlay?.recycle()
2728
overlay = null
29+
output?.recycle()
30+
output = null
31+
}
32+
33+
@Test
34+
fun crop_should_have_correct_size() {
35+
FileUtils.openBitmapInputStream(TestHelper.context(), TestHelper.drawableUri(R.drawable.background)).use {
36+
output = BitmapUtils.crop(it, CGRect(79, 45, 32, 96), BitmapFactory.Options())
37+
38+
assertThat(output!!.width, equalTo(32))
39+
assertThat(output!!.height, equalTo(96))
40+
}
41+
}
42+
43+
@Test
44+
fun cropAndResize_when_portrait_should_have_correct_size() {
45+
FileUtils.openBitmapInputStream(TestHelper.context(), TestHelper.drawableUri(R.drawable.background)).use {
46+
output = BitmapUtils.cropAndResize(it, CGRect(79, 45, 32, 96), CGSize(19, 48), BitmapFactory.Options())
47+
48+
assertThat(output!!.width, equalTo(19))
49+
assertThat(output!!.height, equalTo(48))
50+
}
51+
}
52+
53+
@Test
54+
fun cropAndResize_when_landscaape_should_have_correct_size() {
55+
FileUtils.openBitmapInputStream(TestHelper.context(), TestHelper.drawableUri(R.drawable.background)).use {
56+
output = BitmapUtils.cropAndResize(it, CGRect(79, 45, 32, 96), CGSize(15, 48), BitmapFactory.Options())
57+
58+
assertThat(output!!.width, equalTo(15))
59+
assertThat(output!!.height, equalTo(48))
60+
}
2861
}
2962

3063
@Test
3164
fun overlay_should_overlay_image_at_correct_location() {
32-
val context = InstrumentationRegistry.getInstrumentation().targetContext
3365
val options = BitmapFactory.Options().apply {
3466
inMutable = true
3567
inTargetDensity = DisplayMetrics.DENSITY_DEFAULT
3668
inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
3769
}
38-
background = BitmapFactory.decodeResource(context.resources, R.drawable.background, options)
39-
overlay = BitmapFactory.decodeResource(context.resources, R.drawable.overlay, options)
70+
background = TestHelper.drawableBitmap(R.drawable.background, options)
71+
overlay = TestHelper.drawableBitmap(R.drawable.overlay, options)
4072

4173
BitmapUtils.overlay(background!!, overlay!!, PointF(75f, 145f))
4274

4375
assertThat(background!!.colorSpace, equalTo(overlay!!.colorSpace))
4476
assertThat(background!!.getPixel(75 + 96, 145 + 70), equalTo(overlay!!.getPixel(96, 70)))
4577
}
78+
79+
@Test
80+
fun readImageDimensions_should_return_correct_dimension() {
81+
assertReadImageDimensions(R.drawable.background, 800, 530)
82+
assertReadImageDimensions(R.drawable.overlay, 200, 141)
83+
}
84+
85+
private fun assertReadImageDimensions(@DrawableRes res: Int, width: Int, height: Int) {
86+
val file = TestHelper.drawableUri(res)
87+
FileUtils.openBitmapInputStream(TestHelper.context(), file).use {
88+
val size = BitmapUtils.readImageDimensions(it)
89+
assertThat(size, equalTo(CGSize(width, height)))
90+
}
91+
}
4692
}

photomanipulator/src/androidTest/java/com/guhungry/photomanipulator/ExampleInstrumentedTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.guhungry.photomanipulator;
22

33
import android.content.Context;
4-
import androidx.test.platform.app.InstrumentationRegistry;
4+
55
import androidx.test.ext.junit.runners.AndroidJUnit4;
6+
import androidx.test.platform.app.InstrumentationRegistry;
67

78
import org.junit.Test;
89
import org.junit.runner.RunWith;
910

10-
import static org.junit.Assert.*;
11+
import static org.junit.Assert.assertEquals;
1112

1213
/**
1314
* Instrumented test, which will execute on an Android device.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.guhungry.photomanipulator
2+
3+
import android.graphics.Bitmap
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import com.guhungry.photomanipulator.test.R
6+
import org.hamcrest.CoreMatchers.equalTo
7+
import org.hamcrest.CoreMatchers.instanceOf
8+
import org.hamcrest.Matchers.greaterThan
9+
import org.hamcrest.core.StringEndsWith
10+
import org.hamcrest.core.StringStartsWith
11+
import org.junit.Assert.assertThat
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
import java.io.InputStream
15+
16+
@RunWith(AndroidJUnit4::class)
17+
class FileUtilsAndroidTest {
18+
@Test
19+
fun createTempFile_WhenPrefixSuffix_ShouldReturnTempFileCorrectly() {
20+
val actual = FileUtils.createTempFile(TestHelper.context(), "RNMP_PFEFIX_BEE", MimeUtils.WEBP).apply {
21+
deleteOnExit()
22+
}
23+
24+
assertThat(actual.name, StringStartsWith("RNMP_PFEFIX_BEE"))
25+
assertThat(actual.name, StringEndsWith(".webp"))
26+
}
27+
28+
@Test
29+
fun saveImageFile_ShouldIncreaseFileSize() {
30+
val image = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
31+
val output = FileUtils.createTempFile(TestHelper.context(), "TEST_SAVE_IMAGE", MimeUtils.PNG).apply {
32+
deleteOnExit()
33+
}
34+
35+
assertThat(output.length(), equalTo(0L))
36+
FileUtils.saveImageFile(image, MimeUtils.PNG, 100, output)
37+
38+
assertThat(output.length(), greaterThan(0L))
39+
}
40+
41+
@Test
42+
fun openBitmapInputStream_ShouldReadDrawable() {
43+
val uri = TestHelper.drawableUri(R.drawable.background)
44+
45+
FileUtils.openBitmapInputStream(TestHelper.context(), uri).use {
46+
assertThat(it, instanceOf(InputStream::class.java))
47+
}
48+
}
49+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.guhungry.photomanipulator
2+
import android.graphics.BitmapFactory
3+
import androidx.annotation.DrawableRes
4+
import androidx.test.platform.app.InstrumentationRegistry
5+
6+
object TestHelper {
7+
fun context() = InstrumentationRegistry.getInstrumentation().targetContext
8+
fun packageName() = context().packageName
9+
fun tempDirectory() = context().cacheDir
10+
11+
fun drawableUri(@DrawableRes res: Int) = "android.resource://${packageName()}/${res}"
12+
fun drawableBitmap(@DrawableRes res: Int, options: BitmapFactory.Options) = BitmapFactory.decodeResource(context().resources, res, options)
13+
}

0 commit comments

Comments
 (0)