Article image
Karol Attekita
Karol Attekita26/04/2023 16:59
Share

Escrevendo testes de interface com Snapshot Testing para iOS

    Testes são fundamentais para garantir a qualidade de um software e com certeza é algo que um bom desenvolvedor deveria se aprofundar por se importar em realmente entregar algo de valor. Acredito que um dos principais motivos que levam desenvolvedores a negligenciar testes é justamente porque um código mal escrito dificilmente será testável e isso acaba evidenciando outros problemas e se tornando uma tarefa árdua.

    Apesar dos testes unitários serem mais difundidos por justamente estarem na base do que chamamos de pirâmide de testes e garantirem o funcionamento da menor fração de lógica do seu código. Existem ainda outros tipos de testes e nesse artigo vamos falar sobre Snapshot Testing e entender na prática como esse tipo de teste funciona para o desenvolvimento iOS.

    Enquanto os testes unitários irão focar nas funcionalidades do seu código, os testes de interface vai focar na validação para assegurar uma boa experiencia do usuário. Dentro desse grupo de testes temos os UITests e também Snapshot Tests. Basicamente a principal diferença dos dois é que os testes de UI servem para validação de fluxos, nesse tipo de teste, você vai simular as interações do usuário e validar se a interface esta se comportando como esperado, por exemplo, se estamos visualizando as informações que deveríamos visualizar, se o usuário é redirecionado para a tela correta, se o estado de interface é o esperado … e por ai vai.

    No entanto os Snapshot Tests vai basicamente validar o aspecto visual da sua interface e principalmente dos seus componentes. Esse é um tipo de teste muito utilizado para times que trabalham com componentização e principalmente utilizam design System nas suas implementações. Através desse teste conseguimos validar se aquele componente tem a aparência esperada para os seus diversos estados.

    Como funciona? Não existe magica nesse sentido, ao rodar os testes o compilador vai gerar capturas desses componentes e compara-las, e essa comparação é feita pixel a pixel. No entanto, é claro, para que essa validação seja feita você precisa fornecer a imagem referencia que será utilizada na comparação, e nessas comparação também podemos definir uma margem de erro para tolerar pequenas variações.

    Para implementar esse tipo de teste em nossa aplicação podemos utilizar uma biblioteca de código aberto, chamada iOSSnapshotTestCase. Um "snapshot test case" pega uma UIView ou CALayer configurada e usa os métodos necessários do UIKit ou Core Animation para gerar uma captura de tela e fazer a validação com uma imagem referencia. Isso é extremamente útil quando vários times utilizam os mesmos componentes e você precisa assegurar que alterações nesses componentes não foram feitas por engano.

    Vamos agora criar um teste exemplo para entender como funciona na prática, para isso vamos seguir os passos abaixo:

    1. Crie um novo target de teste para o seu projeto

    image

    2. Instale o iOSSnapshotTestCase usando o Cocoapods, adicionando a biblioteca em seu Podfile:

    
    target "Tests" do
    use_frameworks!
    pod 'iOSSnapshotTestCase'
    end
    
    

    Você também pode instalar através do Swift Package Manager, adicionando o seguinte código no seu arquivo Package.swift

    
    dependencies: [
    .package(url: "https://github.com/uber/ios-snapshot-test-case.git", from: "8.0.0"),
    ],
    
    

    3. Configure o Scheme

    Adicione uma variável de ambiente no seguinte caminho com o nome e valor mencionados.

    App Target -> Edit Scheme -> Run -> Environment Variables

    image

    FB_REFERENCE_IMAGE_DIR: $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages

    IMAGE_DIFF_DIR: $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/FailureDiffs

    Usamos o FB_REFERENCE_IMAGE_DIR e IMAGE_DIFF_DIR para armazenar imagens de referência e imagens de falha/diferenças em um caminho específico.

    4. Crie um novo caso de teste que herde de FBSnapshotTestCase:

    
    swiftCopy code
    import XCTest
    import iOSSnapshotTestCase
    
    
    class MyViewControllerTests: FBSnapshotTestCase {
    
    
      override func setUp() {
          super.setUp()
          self.recordMode = false // defina como true se quiser gravar novos snapshots
      }
    
    
      func testMyViewController() {
          let viewController = MyViewController()
          self.FBSnapshotVerifyView(viewController.view)
      }
    }
    

    Nesse exemplo estamos criando um teste de snapshot para nossa MyViewController. Esse teste então irá capturar toda tela e fazer a comparação. 

    Podemos observar que temos uma variável chamada recordMode que aceita um valor do tipo verdadeiro ou falso. Essa flag indica que o teste ira capturar imagens de referencia quando rodar, então é importante entender que para gerar as imagens de referencia precisamos setar o valor para verdadeiro e para validar rodamos o teste com recodMode igual a falso. Deste modo, sempre rodaremos o teste com o recordMode ativado pelo menos uma vez, para capturarmos as imagens que serão usadas como referência.

    Criamos também um método de teste chamado "testMyViewController" que cria uma nova instância de MyViewController e verifica sua visualização usando o método FBSnapshotVerifyView.

    Agora se rodarmos o teste com o recordMode como verdadeiro, observaremos que algumas imagens serão geradas na pasta que definimos nas configurações (Tests/ReferenceImages’). Se por acaso fizermos alguma alteração visual em nossa MyViewController e rodarmos esse teste novamente com o recordMode como falso, observaremos que novas imagens serão geradas na pasta que definimos nas configurações para imagens de falha (Tests/FailureDiffs).

    Desta forma, quando um teste falha, você consegue verificar a diferença entre a referencia e a imagem que foi capturada e conseguira identificar possíveis comportamentos nao esperados nos seus componentes de interface. Os benefícios do teste de snapshot são numerosos pois ele permite que os desenvolvedores testem a aparência visual de suas interfaces sem precisar escrever testes de UI complexos. De todo modo é importante dizer que testes de snapshot e testes de UI servem para propósitos diferentes, assim como explicado anteriormente e é preciso ter bom senso em entender quando realmente faz sentido a implementação desse tipo de teste em seu fluxo de desenvolvimento.

    Como vimos no exemplo, é relativamente fácil escrever um teste de snapshot, Isso pode economizar tempo e tornar o processo de teste mais eficiente. Além de ajudar a detectar regressões visuais cedo no processo de desenvolvimento, antes que se tornem mais difíceis de corrigir.

    Share
    Comments (6)
    Cristian Francisco
    Cristian Francisco - 14/12/2023 08:51

    Obrigado por transbordar conhecimento!

    Valeu!

    VR

    Vitor Rezende - 27/04/2023 11:04

    Que legal, também te acompanho em outras mídias, fico feliz de ve-la aqui.


    Obrigado pela contribuição com a comunidade!

    Iury Silva
    Iury Silva - 27/04/2023 10:46

    Karol está na Dio! Acompanho suas dicas em outras plataformas, sua didática e conteúdo são muito bons grato por todo vídeo seu que vi!

    Afonso Simão
    Afonso Simão - 27/04/2023 08:25

    olha quem esta aqui!!!

    adorei o artigo.

    Luiz Rios
    Luiz Rios - 26/04/2023 19:27

    Attekita aqui 😍

    Paula Suzart
    Paula Suzart - 26/04/2023 18:18

    Amei o artigo, acho perfeito o mundo IOS.