Introdução: Por que testar aplicações Swift?
O desenvolvimento de uma aplicação iOS ou macOS de qualidade é impossível sem testes adequados. No ecossistema Swift, existe um poderoso framework XCTest que permite escrever todos os três níveis de testes: unitários (unit), de integração (integration) e ponta a ponta (E2E). Cada um desses níveis é responsável por sua própria área e ajuda a identificar erros em diferentes estágios do desenvolvimento.
Neste artigo, vamos analisar como configurar e escrever testes para aplicações Swift corretamente, usando práticas e ferramentas modernas. Você aprenderá as diferenças entre os tipos de testes e obterá exemplos de código prontos que podem ser aplicados imediatamente no seu projeto.
Testes Unitários em Swift
Testes unitários são a base da pirâmide de testes. Eles verificam o funcionamento de componentes individuais (métodos, classes, structs) isolados de dependências externas.
Configuração de Testes Unitários no Xcode
Para criar um target de teste no Xcode, ao criar o projeto, basta marcar a opção "Include Tests". Se o projeto já existir, adicione um novo target: File → New → Target → iOS Unit Testing Bundle.
Exemplo Básico de Teste Unitário
Vamos considerar um exemplo simples de teste de uma calculadora:
import XCTest
final class CalculatorTests: XCTestCase { var calculator: Calculator! override func setUpWithError() throws { calculator = Calculator() } override func tearDownWithError() throws { calculator = nil } func testAddition() { // Given let a = 5 let b = 3 // When let result = calculator.add(a, b) // Then XCTAssertEqual(result, 8, "5 + 3 deve ser igual a 8") } func testDivisionByZero() { XCTAssertThrowsError(try calculator.divide(10, 0)) { error in XCTAssertEqual(error as? CalculatorError, CalculatorError.divisionByZero) } }}Melhores Práticas para Testes Unitários
- Isolamento: Cada teste deve ser independente. Use
setUpWithErroretearDownWithErrorpara preparação e limpeza. - Padrão AAA: Arrange (preparação), Act (ação), Assert (verificação).
- Uma verificação por teste: O teste ideal verifica apenas um comportamento.
- Nomenclatura: Use nomes descritivos:
testMethodName_WhenCondition_ExpectedResult.
Testes de Integração em Swift
Testes de integração verificam a interação entre componentes: trabalho com banco de dados, requisições de rede, sistema de arquivos. Ao contrário dos testes unitários, aqui não simulamos (mock) tudo, mas testamos interações reais.
Testando Core Data
Exemplo de teste de trabalho com Core Data:
import XCTest@testable import MyApp
final class CoreDataIntegrationTests: XCTestCase { var coreDataStack: CoreDataStack! override func setUpWithError() throws { coreDataStack = CoreDataStack(inMemory: true) // Usamos armazenamento in-memory } func testSaveAndFetchUser() { // Arrange let user = User(context: coreDataStack.viewContext) user.name = "João" user.age = 30 // Act try? coreDataStack.viewContext.save() let fetchRequest: NSFetchRequest<User> = User.fetchRequest() let users = try? coreDataStack.viewContext.fetch(fetchRequest) // Assert XCTAssertEqual(users?.count, 1) XCTAssertEqual(users?.first?.name, "João") }}Testando a Camada de Rede
Para testes de integração de rede, use