Guia Definitivo de Testes no iOS: Do Unitário ao CI/CD Frameworks: Swift Testing, XCTest, SwiftData, XCUITest
Este é um guia de estudos sobre testes no ecossistema da Apple. Se você já construiu um aplicativo, sabe que garantir que ele continue funcionando perfeitamente a cada nova atualização, refatoração ou adição de funcionalidade é o verdadeiro desafio. É exatamente para resolver esse problema que utilizamos os testes automatizados. Em sua essência, um teste automatizado é simplesmente um código que você escreve com um único objetivo: verificar se o seu código principal (o aplicativo em si) está se comportando como deveria.
Em vez de testar o app manualmente no simulador do Xcode repetidas vezes, você cria roteiros automatizados que rodam em frações de segundo. Eles atuam como uma rede de segurança: se uma refatoração futura quebrar algo que já funcionava, o teste falha imediatamente, barrando o erro antes que ele chegue ao usuário final. Para aplicar essa proteção de forma eficiente e sem sobrecarregar o projeto, dividimos os testes em diferentes categorias, cada uma com seu próprio foco.

Nos testes unitários, o foco é a regra de negócio. Eles devem ser extremamente rápidos (rodar em milissegundos) e não devem depender de fatores externos (como internet ou o banco de dados real).
Objetivo: Testar a menor parte do código de forma isolada (geralmente uma função ou método).
Framework: Swift Testing (macros @Test, @Suite).
Validações: Uso de #expect para checagens que podem falhar sem parar o teste e #require para desembrulhar opcionais e parar o teste em caso de erro crítico.
//NomeDoArquivoTests.swift
//Inicie importando testing
import Testing
import Foundation
//Importe o projeto com o atributo @testing para permitir o acesso a tipos internos
@testable import NomeDoSeuProjeto
//O macro @Suite serve para aplicar a todos os testes dentro deste grupo
@Suite("Testes do NomeDoSeuArquivo")
//Usamos quando o teste for interagir com códigos que exigem a thread principal
@MainActor
//Este macro substitui o test prefixo do XCTest, informando que há um teste
@Test("Verifica se todayRange calcula corretamente o início e o fim do dia")
func todayRange() {
let calendario = Calendar.current
//Chama a função estática diretamente do ViewModel
let (inicioDoDia, fimDoDia) = DashboardViewModel.todayRange(calendar: calendario)
//Verifica se a data 'inicioDoDia' realmente começa à meia-noite (00:00:00)
let componentesInicio = calendario.dateComponents([.hour, .minute, .second], from: inicioDoDia)
#expect(componentesInicio.hour == 0, "A hora inicial deve ser 0 (meia-noite)")
#expect(componentesInicio.minute == 0, "O minuto inicial deve ser 0")
#expect(componentesInicio.second == 0, "O segundo inicial deve ser 0")
}
//Utilizamos #require para validar condições essenciais para a continuidade de um teste.
let bebidasSalvas = try context.fetch(FetchDescriptor<Drink>())
let bebida = try #require(bebidasSalvas.first, "A bebida deveria ter sido encontrada no banco")