Skip to content

Commit f6a91a6

Browse files
jselboJoshua Selbo
andauthored
Replace mockito-android mock maker implementation with dexmaker-mockito-inline (#3792)
Co-authored-by: Joshua Selbo <jselbo@meta.com>
1 parent aa2298a commit f6a91a6

16 files changed

Lines changed: 124 additions & 238 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ jobs:
107107
strategy:
108108
matrix:
109109
# Minimum supported and maximum available.
110-
android-api: [ 26, 33 ]
110+
android-api: [ 28, 33 ]
111111

112112
# All build steps
113113
steps:

build.gradle.kts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ plugins {
1515
id("com.github.ben-manes.versions") version "0.51.0"
1616
id("mockito.root.releasing-conventions")
1717

18-
// Top-level android plugin declaration required for :mockito-integration-tests:android-tests to work
19-
alias(libs.plugins.android.application) apply false
18+
// Top-level android plugin declarations required for android modules to work.
19+
// Use id() instead of alias() because AGP is on the buildSrc classpath.
20+
id("com.android.application") apply false
21+
id("com.android.library") apply false
2022
}
2123

2224

buildSrc/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies {
1212
implementation(libs.gradleplugin.spotless.googleJavaFormat)
1313
implementation(libs.gradleplugin.license)
1414

15+
implementation(libs.gradleplugin.android)
1516
implementation(libs.gradleplugin.nexusPublish)
1617
implementation(libs.gradleplugin.shipkit.changelog)
1718
implementation(libs.gradleplugin.shipkit.autoVersion)

buildSrc/settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
dependencyResolutionManagement {
22
repositories {
33
mavenCentral()
4+
google()
45
gradlePluginPortal()
56
}
67
versionCatalogs {

buildSrc/src/main/kotlin/mockito.publication-conventions.gradle.kts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,50 @@ plugins.withType<JavaLibraryPlugin>().configureEach {
150150
}
151151
}
152152

153+
// Android library publication conventions
154+
plugins.withType<com.android.build.gradle.LibraryPlugin>().configureEach {
155+
val licenseSpec = copySpec {
156+
from(project.rootDir)
157+
include("LICENSE")
158+
}
159+
160+
afterEvaluate {
161+
val androidExtension = extensions.getByType<com.android.build.gradle.LibraryExtension>()
162+
163+
val sourcesJar by tasks.registering(Jar::class) {
164+
archiveClassifier.set("sources")
165+
from(androidExtension.sourceSets.getByName("main").java.srcDirs)
166+
with(licenseSpec)
167+
}
168+
169+
publishing {
170+
publications {
171+
register<MavenPublication>("mockitoLibrary") {
172+
from(components["release"])
173+
artifact(sourcesJar)
174+
}
175+
}
176+
}
177+
178+
tasks.named<GenerateMavenPom>("generatePomFileForMockitoLibraryPublication") {
179+
doLast {
180+
destination.readText().let { pomContent ->
181+
require(pomContent.contains("<artifactId>${project.base.archivesName.get()}</artifactId>")) {
182+
"POM file does not contain the correct artifactId: ${project.base.archivesName.get()}"
183+
}
184+
require(pomContent.contains("<name>${project.base.archivesName.get()}</name>")) {
185+
"POM file does not contain the correct name: ${project.base.archivesName.get()}"
186+
}
187+
}
188+
}
189+
}
190+
191+
tasks.build {
192+
dependsOn("publishAllPublicationsToLocalRepository")
193+
}
194+
}
195+
}
196+
153197
tasks.withType<GenerateModuleMetadata>().configureEach {
154198
enabled = false
155199
}

gradle/libs.versions.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[versions]
22
bytebuddy = "1.17.7"
3+
dexmaker = "2.28.6"
34
errorprone = "2.42.0"
45
jacoco = "0.8.13"
56
junit4 = "4.13.2"
@@ -23,7 +24,7 @@ autoservice = { module = "com.google.auto.service:auto-service", version = "1.1.
2324
bnd-gradle = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "gradleplugin-aQute-bnd" }
2425
bytebuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "bytebuddy" }
2526
bytebuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "bytebuddy" }
26-
bytebuddy-android = { module = "net.bytebuddy:byte-buddy-android", version.ref = "bytebuddy" }
27+
dexmaker-mockito-inline = { module = "com.linkedin.dexmaker:dexmaker-mockito-inline", version.ref = "dexmaker" }
2728
equinox = { module = "org.eclipse.platform:org.eclipse.osgi", version = "3.23.200" }
2829
errorprone = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone" }
2930
errorprone-test-api = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorprone" }
@@ -48,6 +49,7 @@ gradleplugin-animalSniffer = { module = "ru.vyarus:gradle-animalsniffer-plugin",
4849
gradleplugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "gradleplugin-aQute-bnd" }
4950
gradleplugin-errorprone = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "gradleplugin-errorprone" }
5051
gradleplugin-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "gradleplugin-spotless" }
52+
gradleplugin-android = { module = "com.android.tools.build:gradle", version.ref = "gradleplugin-android" }
5153
gradleplugin-spotless-googleJavaFormat = { module = "com.google.googlejavaformat:google-java-format", version = "1.28.0" }
5254
gradleplugin-license = { module = "com.github.hierynomus.license:com.github.hierynomus.license.gradle.plugin", version = "0.16.1" }
5355
gradleplugin-nexusPublish = { module = "io.github.gradle-nexus:publish-plugin", version = "2.0.0" }
@@ -60,4 +62,5 @@ animalSniffer-java = { module = "org.codehaus.mojo.signature:java18", version =
6062

6163
[plugins]
6264
android-application = { id = "com.android.application", version.ref = "gradleplugin-android" }
65+
android-library = { id = "com.android.library", version.ref = "gradleplugin-android" }
6366
kotlin = { id = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin"}

mockito-core/src/main/java/org/mockito/Mockito.java

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,23 +134,41 @@
134134
*
135135
* With Mockito version 2.6.1 we ship "native" Android support. To enable Android support, add the `mockito-android` library as dependency
136136
* to your project. This artifact is published to the same Mockito organization and can be imported for Android as follows:
137+
* <p>
138+
* Version catalog:
139+
* <pre class="code"><code class="toml">
140+
* [versions]
141+
* mockito = "5.23.0"
137142
*
138-
* <pre class="code"><code>
139-
* repositories {
140-
* mavenCentral()
141-
* }
143+
* [libraries]
144+
* mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" }
145+
* mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito" }
146+
* </code></pre>
147+
* App Gradle file:
148+
* <pre class="code"><code class="kotlin">
142149
* dependencies {
143-
* testCompile "org.mockito:mockito-core:+"
144-
* androidTestCompile "org.mockito:mockito-android:+"
150+
* testImplementation(libs.mockito)
151+
* androidTestImplementation(libs.mockito.android)
145152
* }
146153
* </code></pre>
154+
* <p>
155+
* <b>New in Mockito 5.23.0 - Kotlin support!</b> The `mockito-android` artifact now uses
156+
* <a href="https://github.com/linkedin/dexmaker">dexmaker-mockito-inline</a> under the hood to provide inline mocking on Android,
157+
* which supports mocking of final classes and methods. This means it can mock Kotlin classes without having to mark them as {@code open}.
158+
*
159+
* <p>
160+
* Note this requires Android API 28 (Android P) or higher at runtime. Apps with a lower
161+
* {@code minSdk} will still compile, but tests will fail if run on an emulator or device with an API level below 28.
147162
*
148-
* You can continue to run the same unit tests on a regular VM by using the `mockito-core` artifact in your "testCompile" scope as shown
149-
* above. Be aware that you cannot use the <a href="#39">inline mock maker</a> on Android due to limitations in the Android VM.
163+
* <p>
164+
* Note you must set {@code android:extractNativeLibs="true"} in your {@code androidTest/AndroidManifest.xml} for the
165+
* dexmaker native library to be accessible:
166+
*
167+
* <pre class="code"><code>
168+
* &lt;application android:extractNativeLibs="true" /&gt;
169+
* </code></pre>
150170
*
151-
* If you encounter issues with mocking on Android, please open an issue
152-
* <a href="https://github.com/mockito/mockito/issues/new">on the official issue tracker</a>.
153-
* Do provide the version of Android you are working on and dependencies of your project.
171+
* Using `mockito-android` in a non-Android environment is unsupported. For JVM tests, use `mockito-core` directly.
154172
*
155173
* <h3 id="0.2">0.2. <a class="meaningful_link" href="#mockito-inline" name="mockito-inline">Configuration-free inline mock making</a></h3>
156174
*
@@ -1143,8 +1161,6 @@
11431161
* <p>Driven by requirements and patches from Google Android guys Mockito now offers an extension point
11441162
* that allows replacing the proxy generation engine. By default, Mockito uses <a href="https://github.com/raphw/byte-buddy">Byte Buddy</a>
11451163
* to create dynamic proxies.
1146-
* <p>The extension point is for advanced users that want to extend Mockito. For example, it is now possible
1147-
* to use Mockito for Android testing with a help of <a href="https://github.com/crittercism/dexmaker">dexmaker</a>.
11481164
* <p>For more details, motivations and examples please refer to
11491165
* the docs for {@link org.mockito.plugins.MockMaker}.
11501166
*

mockito-core/src/main/java/org/mockito/internal/util/Platform.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ public static boolean isAndroid() {
2525
return System.getProperty("java.vendor", "").toLowerCase(Locale.US).contains("android");
2626
}
2727

28-
public static boolean isAndroidMockMakerRequired() {
29-
return Boolean.getBoolean("org.mockito.mock.android");
30-
}
31-
3228
public static String describe() {
3329
String description =
3430
String.format(
Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
plugins {
2-
id("mockito.java-library-conventions")
2+
id("com.android.library")
33
id("mockito.publication-conventions")
44
}
55

66
description = "Mockito for Android"
77

8-
dependencies {
9-
api(project(":mockito-core"))
10-
implementation(libs.bytebuddy.android)
8+
android {
9+
namespace = "org.mockito.android"
10+
compileSdk = 33
11+
12+
defaultConfig {
13+
minSdk = 21
14+
}
1115
}
1216

13-
tasks.javadoc {
14-
isEnabled = false
17+
dependencies {
18+
api(project(":mockito-core"))
19+
implementation(libs.dexmaker.mockito.inline)
1520
}

mockito-extensions/mockito-android/src/main/java/org/mockito/android/internal/creation/AndroidByteBuddyMockMaker.java

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)