# 测试你的应用

> 测试框架（TestCase）、模拟触摸，以及通过 screenshot 进行视觉比对。

Source: https://crossfly.dev/zh/docs/learn/testing-your-app — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 11. 测试你的应用

> **你将学到：** 用运行在图形运行时中的测试构建一张安全网。
> **前置要求：** [让它响应式](/docs/learn/making-it-responsive)。

## 完整示例（复制、粘贴即可运行）
与其他章节不同，这里的自包含示例是一个完整的 `TestCase`（而非
`MainWindow`）：在 `load()` 中打开界面，在 `runTests()` 中模拟触摸，并把 screenshot 与
golden 进行比对。`DeviceConfig.isTesting = true` 使渲染确定化。原样即可编译。
```java
package com.exemplo;

import dev.crossfly.test.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

public class AdicionarTarefaTest extends TestCase
{
   @Override
   protected void load() throws Exception
   {
      DeviceConfig.isTesting = true;                 // golden 的前提条件（确定性）
      new TarefasScreen().show();
   }

   @Override
   public void runTests() throws Exception
   {
      waitWindow(TarefasScreen.class);               // 等待一个稳定的帧
      type(0, TextField.class, "Comprar pão");       // 在第 1 个 TextField 中输入
      click("Adicionar");                            // 通过文本点击按钮
      shot();                                        // 截图并与 golden 对比
   }

   @Override
   protected void unload() { }
}

class TarefasScreen extends Window                   // 被测试的界面
{
   private final TextField campo = new TextField().caption("Nova tarefa");
   private final Component listaBox = new Component();

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());
      add(LAY_AUTO, campo);

      Button add = new Button("Adicionar");
      add.onAction(c -> {
         String t = campo.getText().trim();
         if (!t.isEmpty()) { listaBox.add(LAY_AUTO, new Label(t)); campo.clearText(); listaBox.setValidLayout(false); repaint(); }
      });
      add(LAY_AUTO, add);

      listaBox.setLayout(new VerticalLayout());
      add(LAY_FILL, listaBox);
   }
}
```
运行测试套件：
```java
new TestSuite().startTests(new TestCase[]{ new AdicionarTarefaTest() });
```
> 下面的代码片段只展示**核心部分**（放入 `onShow()` 内部的内容）。要运行它们，请放进上面的 `MainWindow` 骨架中。

## 测试运行在图形运行时中（不是 JUnit）
每个 `TestCase` 都运行在 paint thread/GL 管线内部；主要断言是 screenshot 的**视觉比对**
（*golden images*）。
```java
public class AdicionarTarefaTest extends TestCase {
   @Override protected void load() throws Exception { new TarefasScreen().show(); }
   @Override public void runTests() throws Exception {
      waitWindow(TarefasScreen.class);
      type(0, TextField.class, "Comprar pão");   // 在字段中输入
      click("Adicionar");                         // 点击按钮
      shot();                                     // 截图并与 golden 对比
   }
   @Override protected void unload() { }
}
```
用 `TestSuite` 运行：
```java
new TestSuite().startTests(new TestCase[]{ new AdicionarTarefaTest() });
```

## ⚠️ 确定性：`DeviceConfig.isTesting`
只有渲染是确定性的，逐像素比对才能匹配。启用
`DeviceConfig.isTesting = true`（固定光标、去除时间戳）—— **没有它，golden 永远不会匹配**。
在 `shot()` 之前使用 `waitWindow(...)`/`waitAnimation()` 来捕获一个**稳定帧**。

## 直接截图
```java
Image atual = Main.getScreenShot(true);   // 捕获帧（不透明）以与 baseline 比较
```

## 本步骤构建的内容
用于**添加/持久化**任务的测试，以及一个界面的**视觉测试**。

## 回顾
`TestCase`（`load`/`runTests`/`unload`）+ `click`/`type`/`shot`；`DeviceConfig.isTesting` 是
golden 的前置要求；捕获稳定帧。

## 下一步
→ [发布](/docs/learn/shipping)

## 另请参阅
- [测试（最佳实践）](/docs/best-practices/testes) · 权威来源：第 31 章 —— 测试
