Entre para a LISTA VIP da Black Friday

00

DIAS

00

HORAS

00

MIN

00

SEG

Clique para saber mais
Alura > Cursos de Mobile > Cursos de iOS > Conteúdos de iOS > Primeiras aulas do curso iOS: garantindo a qualidade do app com testes de UI e snapshot

iOS: garantindo a qualidade do app com testes de UI e snapshot

Teste de integração - Apresentação

Olá, gostaríamos de te dar as boas-vindas ao curso de teste de integração com iOS da Alura, ministrado por Ândriu Coelho.

Audiodescrição: Ândriu se identifica como um homem branco. Tem olhos e cabelos castanhos. Usa barba e camiseta azul-escura com o logotipo da Alura. Ao fundo, estúdio com iluminação azulada e, à direita, estante com decorações.

O que vamos aprender?

Neste curso, vamos estudar sobre teste de integração utilizando o aplicativo Chef Delivery. O objeto é avançar na pirâmide de teste. Anteriormente, testávamos unidades; agora, testaremos fluxos.

Por exemplo, iremos executar um teste automatizado para executar todos os passos pré-definidos e assegurar o principal fluxo do aplicativo, que é a realização de um pedido. Com isso, estudaremos os conceitos e práticas de teste de integração no projeto Chef Delivery.

Outro ponto importante que estudaremos é sobre testes de snapshot. É uma técnica que o Ândriu usa como pessoa desenvolvedora na empresa em que trabalha, o Mercado Livre, que consiste em tirar uma foto do componente para garantir que não haverá inconsistência de layout a cada atualização do aplicativo.

Se ocorrer alguma movimentação ou alteração de cor e tamanho dos componentes, subiremos uma nova foto e o teste comparará se a foto que subimos é igual à foto atual. Dessa forma, conseguimos garantir que, além do fluxo, a parte visual do aplicativo estará assegurada a cada nova entrega.

Pré-requisitos

Como pré-requisito, é importante ter conhecimento em Swift e layouts com SwiftUI, além de concluir os cursos de teste de unidade desta formação.

Gostou do conteúdo que abordaremos? Te esperamos na primeira aula!

Teste de integração - Configurando os testes de UI no Xcode

Para iniciar esse curso, vamos continuar trabalhando com o app Chef Delivery, que já utilizamos nos cursos anteriores de teste. O objetivo é iniciar um novo contexto de teste dentro desse aplicativo.

Conhecendo o projeto

Utilizamos a metodologia ágil, ou seja, temos entregas semanais de novas funcionalidades ou correções de bugs. Com isso, incrementamos o aplicativo com novas atualizações. Além disso, já temos testes de unidade assegurando boa parte da regra de negócio do Chef Delivery.

Qual é o novo problema que enfrentamos? As pessoas usuárias estão insatisfeitas e reclamando de algumas pequenas questões na loja. Um dos comentários mais comuns é que os botões não respondem. Provavelmente, a pessoa usuária tentou clicar em algo dentro do aplicativo e não funcionou.

Outra reclamação é que as telas não carregam, ou seja, há fluxos que não estão adequados. A pessoa usuária precisou fechar o aplicativo e abrir novamente para conseguir utilizá-lo. Temos vários outros problemas relacionados a esse tipo de uso inadequado do aplicativo pelas pessoas usuárias.

E, com isso, a pessoa usuária avalia negativamente o aplicativo, o que impacta na recomendação do nosso app quando outras pessoas o buscam na loja.

Qual é a solução que podemos adotar? Juntamente com a equipe de desenvolvimento e tech leads, uma das tarefas foi analisar o uso de teste de integração no nosso aplicativo.

Até agora, estávamos testando pequenas unidades do nosso código, assegurando que a regra de negócios funcionem. Porém, essa integração entre módulos e telas ainda não foi abordada. A ideia é que possamos, a partir de agora, começar a explorar esse tema de teste de integração.

Configurando teste de integração

Já estamos com o projeto Chef Delivery aberto, utilizando o Xcode, para começar a trabalhar com testes de integração. É muito comum utilizar o Xcode para testes de UI, ou seja, testes de interface - que é um tipo similar de abordagem.

Para começar a escrever esse tipo de teste, precisamos primeiro analisar os targets presentes no projeto. No painel lateral esquerdo, observamos dois targets: ChefDelivery e ChefDeliveryTests. O primeiro é o projeto principal de produção e o segundo é o teste de unidade, criado nos cursos anteriores.

Como vamos abordar testes de UI, precisamos criar um novo target. Para isso, clicamos em "File" no menu superior, selecionamos "New" e escolhemos a opção "Target".

Ao clicar, uma caixa de diálogo se abre para escolher um modelo de target. Na seção de teste no iOS, existem duas opções: teste de unidade e testes de UI. Selecionamos a opção de "UI Testing Bundle" e depois no botão "Next" no canto inferior direito.

Na janela de opções, vamos manter as opções padrão, incluso o nome sugerido ChefDeliveryUITests, e clicamos no botão "Finish" para concluir a criação.

Agora, no painel lateral esquerdo, temos três targets: o projeto, o teste de unidade e o teste de UI, que são os testes de integração que vamos realizar. Ao clicar na pasta "ChefDeliveryUITests", contamos com dois arquivos criados por padrão: ChefDeliveryUITests e ChefDeliveryUITestsLaunchTests. Vamos analisá-los.

ChefDeliveryUITests.swift:

import XCTest

final class ChefDeliveryUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is cal led before the invocation of each test method in the class.
        // In UI tests t is usual ly best to stop immediately when a failure occurs.
        continueAfterFailure = false
        // In UI tests it's important to set the initial state — such as interface orientation — required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws { 
        // Put teardown code here. This method is cal led after the invocation of each test method in the class.
    }

    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testLaunchPerfomance() throws {
        if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
            // This measures how long it takes to launch your application.
            measure(metrics: [XCTApplicationLaunchMetric()]) {
                XCUIApplication().launch()
            }
        }
    }
}

A classe ChefDeliveryUITests utiliza o framework que já conhecemos e utilizamos para escrever os testes de unidade, que é o XCTest.

O primeiro método chamado setUpWithError() é utilizado para fazer uma pré-configuração, seja de uma variável ou de um objeto, antes do teste ser iniciado. O próximo método é o tearDownWithError(), que é o contrário do primeiro. Ele é utilizado para configurar detalhes após a execução de cada teste.

Também temos um método chamado testExample(), que traz um exemplo de teste que vamos analisar. Há também um método testLaunchPerfomance() que mede o desempenho, o qual não vamos utilizar por enquanto.

Vamos apagar tanto o método testLaunchPerfomance() quanto todos os comentários em inglês, deixando apenas o código.

final class ChefDeliveryUITests: XCTestCase {

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    override func tearDownWithError() throws { }

    func testExample() throws {
        let app = XCUIApplication()
        app.launch()
    }
}

O testExample é um exemplo de como o teste de integração inicia. Em let app, temos a instância da aplicação rodando nos testes de UI. Na próxima linha, através do app.launch(), inicializamos o aplicativo.

No menu superior, vamos acessar "Product", clicar na opção "Test" (atalho "Command + U") e aguardar o build ser gerado.

Ao executar o teste, como ele tem apenas uma instrução na linha 20, o aplicativo é inicializado e rapidamente já se fecha. Isso porque ainda não passamos nenhuma instrução para navegar e testar alguma parte do nosso projeto.

Resumindo, esse teste inicial mostra como inicializar o aplicativo. A partir daqui, podemos pensar em qual fluxo testar e como utilizar os testes de UI para isso.

Teste de integração - Escrevendo o primeiro teste de UI para um botão de filtro

Nós acabamos de criar o target para testes de integração, ou seja, para testes de UI no Xcode.

Por padrão, é criado um método chamado testExample(). Vamos alterar a nomenclatura desse método, mas, por enquanto, descobrimos que as duas linhas iniciais desse método nos ajudam a inicializar o aplicativo. A partir daqui, podemos começar a escrever nosso primeiro teste de integração.

Definindo um fluxo de teste

Inicialmente, é preciso definir quais fluxos testaremos. Para isso, vamos abrir o aplicativo e rodar o app.

A primeira tela é o onboarding, que podemos deslizar para entrar na home do app, ou seja, a tela inicial, a partir da qual conseguimos acessar todos os outros fluxos.

Um dos comentários que as pessoas usuárias estavam reportando é que botões não estavam funcionando corretamente e algumas telas não estavam sendo abertas. Com base nisso, podemos mapear alguns fluxos para escrever scripts que executem os testes de forma automática, como se programássemos um robô para executar os passos pré-determinados no código.

Vamos utilizar um exemplo para entender melhor. Quando a pessoa usuária clica no botão de "Filtrar", ela pode escolher uma das opções do popover para filtrar por lojas de 1 até 5 estrelas. A ação desse botão é o primeiro fluxo que vamos garantir utilizando o teste de interface.

Pensando nessa lógica, onde devemos configurar um robô para realizar os testes, qual o primeiro passo que devemos ensinar para que ele consiga encontrar esse botão? A home tem vários componentes, como labels, botões e listas.

Basicamente, queremos que o robô identifique um único botão neste momento, que é o botão de filtrar, para clicar nele e, em seguida, clicar em uma das opções do popover.

Escrevendo primeiro teste de integração

Agora que entendemos nossa demanda, vamos voltar à classe de teste de interface chamada ChefDeliveryUITests().

Em testExample(), logo abaixo da linha 20, onde o aplicativo é inicializado, devemos identificar o botão filtrar. Para fazer isso, vamos criar uma nova constante let chamada filterMenu.

A partir da constante de app, temos acesso ao XCUIApplication, o qual tem uma propriedade chamada buttons que serve para analisar o identificador de um botão. Desse modo, por meio de app.buttons, podemos colocar, entre colchetes e aspas, o identificador FilterMenu.

Assim, supondo que esse botão de menu de filtro seja encontrado, podemos chamar o filterMenu e aplicar o método tap(), que é uma ação feita automaticamente. Em suma, nosso teste inicializará o simulador, identificará, entre todos os botões visíveis, um botão com o identificador FilterMenu e, tocará nesse botão.

ChefDeliveryUITests.swift:

func testExample() throws {
        let app = XCUIApplication()
        app.launch()

        let filterMenu = app.buttons["FilterMenu"]
        filterMenu.tap()
}

É uma boa prática, seja em teste de unidade ou teste de integração, utilizar Asserts, que são instruções que garantem que nosso teste está funcionando corretamente.

Antes de fazer o tap(), seria melhor garantir que o botão existe, para que o teste não clique em um botão que não encontre. Assim, caso o botão com esse identificador não seja encontramos, o teste já quebraria nessa primeira etapa.

Para isso, utilizamos o framework que já conhecemos, o XCTest. Antes do tap(), chamamos o XCTestAssertTrue() e passamos uma condição para que a função avalie se é verdadeira ou falsa. Nesse caso, deve ser verdadeira.

A condição é filterMenu.exists. Se ele existir, o teste avança. Se não existir, o teste falha.

Como segundo parâmetro opcional, podemos colocar uma mensagem de falha para informar a pessoa desenvolvedora qual foi o problema. Por exemplo, a string "O menu de filtro deve existir".

func testExample() throws {
        let app = XCUIApplication()
        app.launch()

        let filterMenu = app.buttons["FilterMenu"]
        XCTAssertTrue(filterMenu.exists, "O menu de filtro deve existir")
        filterMenu.tap()
}

Desse modo, desenvolvemos o primeiro bloco do teste de UI. Abrindo o simulador, relembraremos o primeiro passo: se o teste for bem-sucedido, o robô do teste acessa a página inicial, procura o botão com o identificador filterMenu e realiza um tap (ou seja, clica). Isso abre um popover com várias opções.

Agora, no segundo bloco de código, precisamos ensinar ao teste qual opção ele deve clicar. Vamos selecionar, por exemplo, a opção de "3 estrelas ou mais".

Depois do primeiro bloco, vamos criar uma constante chamada ratingFilterMenu que será igual a app.buttons. Entre colchetes e aspas, passaremos outro identificador, que será RatingFilterButton_3, a terceira opção do popover.

Caso o botão exista, chamamos o ratingFilterMenu.tap() para executar a ação de clique.

Antes disso, também podemos fazer um assert, assim como fizemos anteriormente. Através da função XCTAssertTrue, verificaremos se ratingFilterMenu.exists e informamos, em caso de falha, que "O botão de filtro de 3 estrelas deve existir".

func testExample() throws {
        let app = XCUIApplication()
        app.launch()

        let filterMenu = app.buttons["FilterMenu"]
        XCTAssertTrue(filterMenu.exists, "O menu de filtro deve existir")
        filterMenu.tap()

        let ratingFilterMenu = app.buttons["RatingFilterButton_3"]
        XCTAssertTrue(ratingFilterMenu.exists, "O botão de filtro de 3 estrelas deve existir")
        ratingFilterMenu.tap()
}

Assim, o teste inicial está mais completo.

Executando o teste

Basicamente, existem duas formas de se executar um teste. Se o Xcode estiver com a configuração padrão, ele exibirá um diamante ao lado de cada linha. Basta clicar nele para rodar o teste.

Caso isso não apareça, podemos acessar uma aba específica de teste no painel lateral esquerdo, chamada "Show the Test Navigator" (Mostrar navegador de teste). Nela, são listadas todos os testes do projeto, sejam teste de unidade ou teste de UI.

Neste caso, utilizaremos apenas o target de teste de UI, que é o foco atual. Para evitar confusão, podemos ocultar os testes de unidade clicando no ícone de seta à esquerda para colapsá-los.

Em ChefDeliveryUITest, vamos executar o testExample clicando no ícone de diamante à sua direita. Ocorre um erro, pois não temos um esquema configurado para rodar os testes de UI.

O esquema funciona como um ambiente onde os testes de integração serão executados.

Além de criar o target, precisamos configurar o esquema. Basta clicar em cima do target na barra superior do Xcode e escolher a opção "New Scheme". Na caixa de diálogo, contamos com os campos de "Target" e "Name". Iremos selecionar o target ChefDeliveryUITest e manter o nome sugerido. Por fim, clicamos no botão "OK".

Desse modo, o esquema separa nosso teste de UI dos outros testes. Agora, podemos executar novamente o teste ChefDeliveryUITest, clicando no ícone de diamante. Após iniciar o simulador e gerar o build, a aplicação será inicializada.

O primeiro problema é que a aplicação abre a tela de onboarding. Porém, o teste espera que a home seja carregada para buscar o filterMenu.

Por enquanto, vamos corrigir isso alterando a inicialização do app. No painel lateral esquerdo, vamos acessar a pasta "ChefDelivery > App" para abrir o arquivo ChefDeliveryApp.

Na linha 14, no lugar de HomeView(), vamos abrir o ContentView(), que é a tela inicial do app.

ChefDeliveryApp.swift

struct ChefDeliveryApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Voltamos ao arquivo de teste, abrimos a aba de teste no painel lateral e clicamos novamente no ícone de diamante para executar o ChefDeliveryUITest. Agora, o aplicativo carrega a home, mas o teste ainda falha porque o menu de filtro não foi encontrado.

XCTAssertTrue failed - O menu de filtro deve existir

Ao longo do vídeo, mencionamos propositalmente várias vezes a palavra "identificador", que é uma forma de mostrar ao teste qual elemento ele deve capturar e manipular. A seguir, vamos realizar esse passo para corrigir nosso primeiro teste de integração.

Sobre o curso iOS: garantindo a qualidade do app com testes de UI e snapshot

O curso iOS: garantindo a qualidade do app com testes de UI e snapshot possui 126 minutos de vídeos, em um total de 48 atividades. Gostou? Conheça nossos outros cursos de iOS em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda iOS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas