搭建测试环境:Gradle依赖配置与AndroidX Test归纳总结

好了,到了真正动手的环节。这一章我们聊的是测试环境怎么搭。说实话,很多项目卡在这一步就放弃了——依赖冲突、版本不匹配、运行报错,各种幺蛾子。我个人习惯先把所有依赖写成一份“清单”,再挨个核对,这样心里才踏实。

核心依赖一览

Mock回放测试,说白了就是给网络请求装个“录像机 + 播放器”。我们需要三样东西:

  • Retrofit + OkHttp —— 网络框架本体
  • MockWebServer / MockRetrofit —— 模拟服务器
  • AndroidX Test 全家桶 —— 测试运行器和断言

下面这张图能帮你快速摸清各组件之间的关系:

搭建测试环境:Gradle依赖与AndroidX Test架构 测试层 AndroidX Test Core JUnit 5 / JUnit 4 MockWebServer Mock回放层 本课程 Mock 回放库 (录制/回放拦截器) OkHttp 拦截器链 (自定义 Interceptor) 网络层 Retrofit (接口定义 + 转换器) OkHttp (底层 HTTP 客户端) ⚠ 注意版本兼容性 AndroidX 与旧 support 不共存

一句话总结:你的测试代码通过 AndroidX Test 运行器启动,调用我们封装好的 Mock 回放库,拦截器在 OkHttp 链条里“偷换”请求和响应,最终让 Retrofit 不需要真正的服务器也能工作。

Gradle 依赖配置:建议用 BOM 统一版本

我在项目中遇到过最头疼的事,就是 OkHttp 3.x 和 Retrofit 2.x 的小版本不兼容,导致运行时抛 NoSuchMethodError。所以我的建议是——用 BOM(Bill of Materials) 统一管理版本号。

打开你的 build.gradle(app 模块),在最外层加上这些:

dependencies {
    // —— 测试核心依赖 ——
    testImplementation "androidx.test:core:1.5.0"
    testImplementation "androidx.test:runner:1.5.2"
    testImplementation "androidx.test:rules:1.5.0"
    testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.3"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.3"

    // —— 网络测试依赖 ——
    testImplementation "com.squareup.okhttp3:mockwebserver:4.11.0"
    testImplementation "com.squareup.retrofit2:retrofit:2.9.0"
    testImplementation "com.squareup.retrofit2:converter-gson:2.9.0"

    // (重点)本课程编写的 Mock 回放库
    testImplementation project(':mockreplay-lib')  // 或者发布到本地 maven
}

⚠ 我曾经踩过的坑:如果你同时用了 androidx.test:core-ktx 和 androidx.core:core-ktx,务必核对版本号。曾经因为一个 1.8.0 一个 1.9.0,导致测试一直报 ClassNotFoundException,花了我一下午才追到。解决办法:统一用 androidx.test.ext:junit-ktx:1.1.5 代替散落的扩展包。

AndroidX Test 运行器配置

跑单元测试(非仪器化),关键是在 defaultConfig 里指定测试运行器:

android {
    defaultConfig {
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        // 如果是纯 JUnit 本地测试,保留这一行即可
    }
    testOptions {
        unitTests {
            includeAndroidResources = true  // 需要 Android 资源模拟时打开
        }
    }
}

为什么强调这个?因为 MockWebServer 虽然是纯 Java 库,但如果你在测试里用到了 Context 或者 Resources(比如从 assets 加载回放文件),就必须设置 includeAndroidResources = true,否则会直接挂。

一个真实项目的依赖清单(推荐直接复制)

组件推荐版本作用备注
androidx.test:core1.5.0测试基础类(ApplicationProvider 等)必选
androidx.test:runner1.5.2测试运行器必选
androidx.test:rules1.5.0测试规则(如 InstantTaskExecutorRule)推荐
junit-jupiter-api5.9.3JUnit 5 注解和 APIJUnit 4 用户可换 junit:junit:4.13.2
com.squareup.okhttp3:mockwebserver4.11.0Mock 服务器(模拟 HTTP 响应)必选
com.squareup.retrofit2:retrofit2.9.0Retrofit 核心与生产版本一致
com.squareup.retrofit2:converter-gson2.9.0JSON 自动解析根据你的序列化方案替换
mockreplay-lib0.1.0本课程自研录制/回放拦截器库后续章节详细讲解

💡 小技巧:把 OkHttp 和 Retrofit 的版本号提取成 ext.okhttp_version = '4.11.0' 放在项目根 build.gradle 里,所有模块统一引用。这样以后升级版本只需要改一个地方,不会出现“新版 OkHttp 搭配旧版 Retrofit”的悲剧。

常见冲突与解决方案

我整理了一个 checklist,每次加依赖的时候扫一眼:

  • JUnit 4 vs JUnit 5 混用——如果你用 @Test 注解,需要明确导入 org.junit.Test(JUnit4)还是 org.junit.jupiter.api.Test(JUnit5)。混用会导致测试方法不被发现。
  • kotlin-stdlib 版本不一致——AndroidX Test 某些组件依赖特定 Kotlin 版本。要么统一用 BOM 管理,要么在 configurations.all 里强制指定一个版本。
  • mockwebserver 的 OkHttp 版本冲突——MockWebServer 本身就是 OkHttp 的测试模块,如果生产代码也引用了不同版本的 OkHttp,会报 Duplicate class。我的做法是:把所有 OkHttp 相关依赖(包括 retrofit)都指向同一个版本。
// 强制统一 OkHttp 版本示例(在 app/build.gradle 中)
configurations.all {
    resolutionStrategy {
        force "com.squareup.okhttp3:okhttp:4.11.0"
        force "com.squareup.okhttp3:logging-interceptor:4.11.0"
    }
}

确认环境是否搭建成功

写一个最简单的“冒烟测试”来验证:

import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Test

class SmokeTest {
    private lateinit var mockServer: MockWebServer

    @Before
    fun setUp() {
        mockServer = MockWebServer()
        mockServer.start(8080)
    }

    @Test
    fun testMockServerIsRunning() {
        val url = mockServer.url("/")
        println("Mock server ready at: $url")
        // 能打印出 URL 说明环境没问题
    }

    @After
    fun tearDown() {
        mockServer.shutdown()
    }
}

运行它。如果控制台能看到 Mock server ready at: http://127.0.0.1:8080/,恭喜你,环境已经搭好。剩下的就是往里面塞“录像”数据了。

这一步看似简单,但请务必验证通过——后面所有 Mock 录制和回放测试都依赖这个基础。我曾经在客户现场发现半天跑不通,最后是 Gradle 缓存没清干净导致的。所以建议每次改完依赖后,执行一次 ./gradlew cleanTest test 确保缓存被刷新。