Teste unitário com swift – Parte 1

Todos nós sabemos da importância dos testes unitários no desenvolvimento de software e nesse post vamos montar um pequeno projeto com o teste básico de uma lista a fim de apresentar a estrutura do XCTest, framework de teste utilizado pelo Xcode.

Para começar vamos criar um novo projeto e selecionar a opção “Include Unit Tests”


Após realizar todas as etapas de criação do projeto você poderá observar na hierarquia de pastas que o Xcode criou além da pasta padrão do projeto outra pasta na qual serão incluídos os testes de sua aplicação, reparem que o próprio Xcode já criou um arquivo de teste padrão.

hierarquia de pastas do projeto

Ao abrir o arquivo padrão disponibilizado pelo Xcode nos deparamos com o seguinte código:

Arquivo de teste padrão

Analizando esse código já temos alguns pontos interessantes:

  • Na primeira linha importamos a ferramenta utilizadas em nossos testes, que nesse caso é a XCTest que vem como default no Xcode.
  • Logo após nos deparamos com um import um pouco diferente do convencional pois o mesmo vem com a palavra reservada @testable

O que essa linha faz é importar o seu projeto para o namespace do teste, a palavra chave @testable é necessário por causa da forma como o swift opera com seus modificadores de acesso.
O Swift possui três tipos de modificadores de acesso: Public, Internal e Private, que permitem visibilidade pública a qualquer namespace, visibilidade somente dentro do mesmo namespace e visibilidade apenas da classe/Struct, respectivamente.
Como o teste esta em um namespace separado do projeto, o desenvolvedor precisaria escrever todas as classes e variáveis com o modificador Public, para resolver esse impasse a Apple inseriu a partir da versão 2 do swift a palavra chave @testable, permitindo que as classes e variáveis com o modificador Internal fiquem visíveis no namespace de teste, o que garante a coerência dos modificadores de acesso.

  • Por fim podemos observar quatro funções: setUp, tearDown, testExample e TestPerformanceExample:

Função setUp: Nela será inserido o código para garantir o estado inicial do seu ambiente de teste, como por exemplo, instanciar as controllers que serão testadas. Essa função é chamada antes de cada teste descrito no arquivo.

Função tearDown: Nela você limpará os dados gerados por seu teste. Essa função é chamada após a execução de cada teste descrito no arquivo.

Função testExample: O teste a ser executado, sendo que todos os testes devem obrigatoriamente começar com a palavra test em seu nome.

Função testPerformanceExample: Como no caso anterior, trata-se de um teste, mas como pode ser visto em seu corpo possui um bloco para medição de performance de seu código.

A partir deste ponto vamos começar a escrever o primeiro teste para nossa controller. Para isso vamos precisar cria-la em nosso ambiente e adicionar uma propriedade do mesmo tipo da controller.

1
var viewController: ViewController!

E na função setUp vamos instanciar nossa controller

1
2
3
4
5
6
7
override func setUp() {
        super.setUp()

        viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Controller") as! ViewController
       
        _ = viewController.view
    }

Um ponto importante que devemos destacar nesse neste código é na chamada “_ = viewController.view”, ela é necessária para o carregamento correto da view, segundo a documentação da Apple, uma view só é carregada completamente, e de maneira correta quando requisitada.

Como essa chamada fica sem sentido na leitura de nosso código podemos melhorar a semântica criando uma extension para preload de nossa view controller:

1
2
3
4
5
6
7
8
9
10
import Foundation
import UIKit

extension UIViewController {
   
    func preload() {
        _ = self.view
    }
   
}

E agora podemos utilizar a função de preload no setup de nosso teste, o que garante melhor legibilidade ao nosso código.

1
2
3
4
5
6
7
override func setUp() {
        super.setUp()

        viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Controller") as! ViewController
       
        viewController.preload()
    }

A partir de agora já temos nossa view devidamente instanciada e podemos testa-la. Supondo que minha controller tenha apenas um tableview que deve conter exatamente a quantidade de linhas de meu array, vamos fazer nosso primeiro teste.

1
2
3
4
5
func testNumeroDeItensDaTabelaDeveSerIgualAQuantidadeDeDadosDoArray() {
        viewController.array = ["Item 1", "Item 2", "Item 3"]

        XCTAssertEqual(viewController.tableView?.numberOfRowsInSection(0), 3, "Numero de rows na tabela deve ser igual a 3")
    }

Com nosso primeiro caso de teste construído podemos executá-los através do atalho command+U.
Se você fez corretamente todos os pontos descritos até esse momento seu teste obviamente irá falhar pois ainda não foi construído a controller com todos os elementos que utilizamos aqui.

Agora como desafio insira na sua controller uma propriedade chamada array e um tableview devidamente configurado para que este teste passe na validação.
Esse teste apesar de simples garante que o desenvolvedor não esqueça, por algum motivo, de configurar o datasource do tableview fazendo com que a lista simplesmente deixe de apresentar os dados.

No próximo post continuaremos os testes de nossa lista adicionando fluxo de telas e como estruturar melhor a chamada dos serviços para mockar os dados.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>