Android 单元测试环境搭建

在 Android 中搭建 单元测试(Unit Test) 环境,主要涉及 JUnit、Mockito、Robolectric 等工具。本文介绍如何搭建完整的单元测试环境,并配置 Gradle、测试规则、Mock 依赖 等,确保代码可以高效测试。


1. 配置 Gradle

(1)添加依赖

build.gradle.kts(模块级)中添加单元测试相关依赖:

scss 复制代码
dependencies {
    // JUnit 5 单元测试框架
    testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")

    // Mockito 用于 Mock 依赖
    testImplementation("org.mockito:mockito-core:5.7.0")
    testImplementation("org.mockito:mockito-inline:5.2.0")

    // Kotlin 扩展版 Mockito
    testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0")

    // Robolectric 模拟 Android 组件环境
    testImplementation("org.robolectric:robolectric:4.11.1")

    // 用于测试 Kotlin 协程
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")

    // 断言库(更优雅的断言)
    testImplementation("org.assertj:assertj-core:3.24.2")

    // JSON 解析辅助(用于 Mock API)
    testImplementation("com.google.code.gson:gson:2.10.1")
}

JUnit 5 作为核心测试框架

Mockito 让你可以 Mock 依赖,隔离测试对象

RobolectricJVM 上运行 Android 组件 ,避免依赖真机

Coroutines Test协程测试更稳定


(2)启用 JUnit 5

gradle.properties 中启用 JUnit 5:

ini 复制代码
android.testOptions.unitTests.includeAndroidResources=true

JUnit 4 vs. JUnit 5?

  • JUnit 5(推荐) :支持更多注解、嵌套测试、动态测试
  • JUnit 4:老项目兼容性更好,但不如 JUnit 5 强大

2. 目录结构

单元测试文件放在:

scss 复制代码
app/src/test/java/com/example/app/   // 运行在 JVM,适合单元测试
app/src/androidTest/java/com/example/app/   // 运行在 Android 设备,适合 UI 测试
  • test/ :用于单元测试(Mockito、JUnit、Robolectric)
  • androidTest/ :用于 UI 测试(Espresso、UI Automator)

3. 编写单元测试

(1)测试普通类

示例:测试 Calculator

kotlin 复制代码
class Calculator {
    fun add(a: Int, b: Int) = a + b
}

测试 CalculatorTest

kotlin 复制代码
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class CalculatorTest {
    private val calculator = Calculator()

    @Test
    fun `test addition`() {
        val result = calculator.add(3, 5)
        assertEquals(8, result)
    }
}

JUnit 5 语法 ,更清晰的 assertEquals 断言


(2)Mock 依赖

测试 UserRepository

kotlin 复制代码
class UserRepository(private val apiService: ApiService) {
    suspend fun getUser(): User {
        return apiService.getUser()
    }
}

使用 Mockito Mock ApiService

kotlin 复制代码
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import kotlin.test.assertEquals

class UserRepositoryTest {
    @Mock
    lateinit var apiService: ApiService

    private lateinit var userRepository: UserRepository

    @BeforeEach
    fun setUp() {
        MockitoAnnotations.openMocks(this)
        userRepository = UserRepository(apiService)
    }

    @Test
    fun `get user data successfully`() = runBlocking {
        val mockUser = User("John", 25)
        `when`(apiService.getUser()).thenReturn(mockUser)

        val result = userRepository.getUser()
        assertEquals(mockUser, result)
    }
}

Mock ApiService,避免真实网络请求

使用 runBlocking 处理 suspend 函数


(3)Robolectric 测试 Android 组件

测试 SharedPreferences

kotlin 复制代码
import android.content.Context
import android.content.SharedPreferences
import androidx.test.core.app.ApplicationProvider
import org.junit.Assert.assertEquals
import org.junit.Test
import org.robolectric.RobolectricTestRunner
import org.junit.runner.RunWith

@RunWith(RobolectricTestRunner::class)
class SharedPreferencesTest {
    private val context = ApplicationProvider.getApplicationContext<Context>()
    private val sharedPreferences: SharedPreferences = context.getSharedPreferences("test_prefs", Context.MODE_PRIVATE)

    @Test
    fun `save and retrieve data`() {
        sharedPreferences.edit().putString("key", "value").apply()
        assertEquals("value", sharedPreferences.getString("key", null))
    }
}

Robolectric 让 SharedPreferences 运行在 JVM 上,无需 Android 设备


4. Mock API

使用 MockWebServer 测试 API

kotlin 复制代码
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals

class ApiServiceTest {
    private lateinit var mockWebServer: MockWebServer

    @Before
    fun setup() {
        mockWebServer = MockWebServer()
        mockWebServer.start()
    }

    @After
    fun teardown() {
        mockWebServer.shutdown()
    }

    @Test
    fun `test API response`() {
        mockWebServer.enqueue(MockResponse().setBody("{"name":"John"}"))

        val result = apiService.getUser()
        assertEquals("John", result.name)
    }
}

隔离网络请求,确保 API 逻辑可靠


5. 运行测试

(1)运行所有单元测试

bash 复制代码
./gradlew test

(2)运行指定测试

bash 复制代码
./gradlew testDebugUnitTest --tests "com.example.app.UserRepositoryTest"

(3)生成测试覆盖率报告

bash 复制代码
./gradlew jacocoTestReport

JaCoCo 可以生成代码覆盖率报告,帮助检查哪些代码缺少测试。


总结

目标 方案
核心测试框架 JUnit 5
Mock 依赖 Mockito
模拟 Android 组件 Robolectric
测试 API MockWebServer
异步测试 Coroutines Test
自动化运行 Gradle ./gradlew test

你现在可以在 Android 项目中高效执行单元测试!如果你的项目有特殊需求(比如 RxJava、LiveData ),可以继续优化测试方案。🚀

相关推荐
齊家治國平天下1 小时前
AAOS 电源管理深度解析:休眠/唤醒/功耗优化
android·车载系统·aaos·aosp·电源管理·休眠唤醒·carpowermanager
Xzaveir2 小时前
企业号码展示不可观测怎么办:状态机、拨测事件与异常回放
android·人工智能
2501_916007472 小时前
iOS和macOS应用程序性能分析和优化工具使用综合指南
android·macos·ios·小程序·uni-app·iphone·webview
黄林晴2 小时前
Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南
android
恋猫de小郭3 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter
HLC++16 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼19 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼20 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon20 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户69371750013841 天前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端