Testes em Swift: unit, integration, e2e — nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Testes Avançados em Swift: Unit, Integration e E2E



Testes não são apenas uma verificação, mas a base de um código confiável. Em um nível avançado, o desenvolvedor Swift não precisa apenas escrever testes, mas construir adequadamente a pirâmide de testes: desde testes unitários rápidos até cenários complexos de ponta a ponta (e2e). Neste artigo, abordaremos técnicas avançadas para projetos iOS/macOS: trabalho com dependências, testes de integração CoreData e automação de UI.



1. Testes Unitários: Gerenciamento de Dependências e Mocks



Em um nível avançado, os testes unitários devem ser isolados. A técnica chave é a Injeção de Dependência (DI). Em vez de testar a camada de rede real ou o banco de dados, substituímos por mocks.



Exemplo: Protocolo e DI

protocol NetworkServiceProtocol {    func fetchData(completion: @escaping (Result<String, Error>) -> Void)}

class ViewModel { private let networkService: NetworkServiceProtocol init(networkService: NetworkServiceProtocol) { self.networkService = networkService } func loadData() { networkService.fetchData { result in // processamento } }}

// Mock para testesclass MockNetworkService: NetworkServiceProtocol { var shouldReturnError = false func fetchData(completion: @escaping (Result<String, Error>) -> Void) { if shouldReturnError { completion(.failure(NSError(domain: "test", code: -1))) } else { completion(.success("Mock data")) } }}


No teste, você cria um MockNetworkService e o passa para o ViewModel. Isso permite verificar cenários de erro e sucesso sem uma API real.



XCTestExpectation para Assincronia

func testViewModelLoadDataSuccess() {    let mock = MockNetworkService()    let viewModel = ViewModel(networkService: mock)        let expectation = self.expectation(description: "Data loaded")        viewModel.loadData()        // Simula chamada assíncrona    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {        expectation.fulfill()    }        waitForExpectations(timeout: 1.0)    // Verifica o estado do ViewModel}


2. Testes de Integração: CoreData e Trabalho com Dados Reais



Os testes de integração verificam a interação entre componentes. Para CoreData, usamos um contêiner in-memory para não poluir o banco de dados principal.



Configuração do CoreData In-Memory

class CoreDataTestStack {    lazy var persistentContainer: NSPersistentContainer = {        let container = NSPersistentContainer(name: "MyModel")        let description = NSPersistentStoreDescription()        description.type = NSInMemoryStoreType        container.persistentStoreDescriptions = [description]        container.loadPersistentStores { _, error in            if let error = error {                fatalError("Failed to load store: \\(error)")            }        }        return container    }()        var context: NSManagedObjectContext {        return persistentContainer.viewContext    }}


Exemplo de Teste de Integração

func testSaveAndFetchUser() {    let stack = CoreDataTestStack()    let repository = UserRepository(context: stack.context)        // Cria um usuário    let user = User(context: stack.context)    user.name = "Test User"    user.age = 30        try? stack.context.save()        // Verifica se os dados foram salvos    let fetchRequest: NSFetchRequest<User> = User.fetchRequest()    let users = try? stack.context.fetch(fetchRequest)        XCTAssertEqual(users?.count, 1)    XCTAssertEqual(users?.first?.name, "Test User")}


Importante: após cada teste, limpe o contexto para que os testes não interfiram uns nos outros.

Blogs

Book Recommendations