Android

dependencies {
    androidTestImplementation("dev.tracera:tracera-android:<version>")
    // Optional — richer screenshots (quality/scale) + hierarchy via UiDevice:
    // androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
    // Robolectric (host):
    // testImplementation("dev.tracera:tracera-android:<version>")
}

需要 JDK ≥ 17、Android minSdk ≥ 26 以及 AndroidX Test(JUnit 4 / AndroidJUnitRunner)。推荐 @RunWith(TraceraAndroidJUnit4::class)(见 自动化测试适配器)。tracera-android on Maven Central。

环境变量与运行模式:自动化测试适配器。

通过 testInstrumentationRunnerArguments(或 am instrument -e)设置 TRACERA_*。

android {
    defaultConfig {
        testInstrumentationRunner = "dev.tracera.TraceraAndroidJUnitRunner"
        testInstrumentationRunnerArguments += mapOf(
            "TRACERA_BASE_URL" to "https://app.example",
            "TRACERA_AUTOTEST_TOKEN" to System.getenv("TRACERA_AUTOTEST_TOKEN")!!,
            "TRACERA_PROJECT_ID" to "1",
        )
    }
}

绑定 testCaseId 与 autotestName

照常使用 JUnit 4 / AndroidX Test 标准 API,并从 dev.tracera 导入 Tracera。

在声明时(推荐 — 即使测试体提前跳过也会绑定):

import dev.tracera.TraceraAndroidJUnit4
import dev.tracera.Tracera
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(TraceraAndroidJUnit4::class)
class LoginTest {
    @Tracera.Id(42, name = "e2e/login")
    @Test
    fun login() {
        assert(true)
    }
}

在测试体内:

import dev.tracera.TraceraAndroidJUnit4
import dev.tracera.Tracera
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(TraceraAndroidJUnit4::class)
class LoginTest {
    @Test
    fun login() {
        Tracera.testCase(42, "e2e/login")
        assert(true)
    }
}

跳过

使用标准 JUnit skip(Assume.assumeTrue、@Ignore 等)。跳过原因会写入结果的 comment。

步骤

使用 Tracera.step("…") { … },协程用 Tracera.suspendStep("…") { … }。嵌套用 Tracera.step("…") { … }。@Before / @After 中的步骤进入结果的 前置 / 后置;测试体内的步骤进入 测试。@BeforeClass / @AfterClass 不上报。

设备上请使用 Tracera.step("…") { … } — ART 不支持方法级步骤插桩。在 Robolectric / host JVM 上,方法上的 @Tracera.Step 与其他 JVM 运行器一样可用。

import dev.tracera.TraceraAndroidJUnit4
import dev.tracera.Tracera
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(TraceraAndroidJUnit4::class)
class CheckoutTest {
    @Before
    fun openShop() {
        Tracera.step("open shop") { }
    }

    @Tracera.Id(10, name = "e2e/checkout")
    @Test
    fun checkout() {
        Tracera.step("body outer") {
            Tracera.step("nested leaf") { }
        }
        Tracera.step("pay") { }
    }
}

注释、错误与附件

注释、错误与附件:自动化测试适配器。

Tracera.comment("result-level note")
Tracera.error("result-level error text")
Tracera.step("open login") {
    Tracera.comment("landed on login")
}

截图与设备调试

截图、logcat 与窗口层次为可选(不会自动附加)。把三条 rule 贴到测试类(或基类)上。截图无需额外依赖;仅当你需要 Tracera.screenshot 的 quality / scale(以及基于 UiDevice 的 hierarchy)时,再添加 androidx.test.uiautomator:uiautomator。

ScreenshotRule.Mode:FAILURE(默认)、SUCCESS 或 END。

import dev.tracera.LogcatRule
import dev.tracera.ScreenshotRule
import dev.tracera.Tracera
import dev.tracera.TraceraAndroidJUnit4
import dev.tracera.WindowHierarchyRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(TraceraAndroidJUnit4::class)
class LoginDebugTest {
    @get:Rule
    val screenshots = ScreenshotRule(mode = ScreenshotRule.Mode.FAILURE, fileName = "failure.png")

    @get:Rule
    val logcat = LogcatRule()

    @get:Rule
    val hierarchy = WindowHierarchyRule()

    @Tracera.Id(42, name = "e2e/login")
    @Test
    fun login() {
        // Optional mid-test shot:
        // Tracera.screenshot("login.png", quality = 90, scale = 1.0f)
        assert(true)
    }
}

参数化测试

使用 @RunWith(Parameterized::class)。在测试方法上加 @Tracera.Id。可选 name 可用 {param_id} — JUnit 测试名(例如 login[ok])。若未指定 name,则 autotestName 取 JUnit 测试名。构造函数字段不会填进模板:需要写进名称时,在测试内调用 Tracera.testCase。

import dev.tracera.Tracera
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
class LoginRows(private val login: String) {
    companion object {
        @JvmStatic
        @Parameterized.Parameters(name = "{0}")
        fun data() = listOf(arrayOf("ok"), arrayOf("sso"))
    }

    @Before
    fun openForm() {
        Tracera.step("open form") { }
    }

    @Tracera.Id(42, name = "login as {param_id}")
    @Test
    fun login() {
        assert(login.isNotEmpty())
    }
}