Testes automatizados de UI
O framework de testes do CrossFly não é JUnit. Cada TestCase roda dentro do runtime gráfico
(paint thread, EventsProcessor, pipeline GL), e a asserção principal é a comparação visual de
screenshots contra imagens-referência (golden images). Portal para o
Capítulo 31.
Anatomia de um TestCase
public class LoginTest extends TestCase {
@Override protected void load() throws Exception {
new LoginScreen().show(); // monta a tela sob teste
}
@Override public void runTests() throws Exception {
waitWindow(LoginScreen.class);
type(0, TextField.class, "[email protected]"); // digita no 1º TextField
type(1, TextField.class, "senha123");
click("Entrar"); // clica no botão com esse texto
shot(); // captura e compara com o golden
waitWindow(HomeScreen.class);
shot();
}
@Override protected void unload() { /* limpa estado */ }
}
Interação: click(...), type(...), enter(), penDown/penUp/penDrag(...), setText(...).
Descoberta: find(index, Classe) / find(texto, Classe). Sincronização: waitWindow(...),
waitAnimation(), waitUIidle(...).
Agrupar e rodar — TestSuite
TestSuite suite = new TestSuite();
suite.startTests(new TestCase[]{ new LoginTest(), new CadastroTest() });
A suite roda cada teste, compara os shot() com os goldens e reporta (success/fail/log).
⚠️ Determinismo é pré-requisito: DeviceConfig.isTesting
A comparação pixel-a-pixel só casa se a renderização for determinística. Ligue
DeviceConfig.isTesting = true — isso fixa o cursor, remove timestamps e torna TimePicker/relógio
estáveis. Sem isso, o golden nunca bate (cursor piscando, hora atual, etc. mudam a imagem).
Sem UI: WindowlessTestCase
Para lógica que não precisa de tela (repository, formatação), estenda WindowlessTestCase — roda no
runtime, mas sem montar UI.
Gerar as imagens da doc
Os mesmos screenshots de teste servem para gerar as imagens da documentação/loja:
Main.getScreenShot(true).toPng("prefixo_").
Boas práticas
- Sempre
DeviceConfig.isTesting = truena bateria de testes. - Use
waitWindow(...)/waitAnimation()antes deshot()— capture um frame estável. - Um golden por estado visual relevante; regenere ao mudar a UI de propósito.
Erros comuns
- Golden que “some vez sim, vez não” → faltou
isTesting/waitAnimation(frame instável). shot()antes da janela estar totalmente visível.