Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Testes no CI com Flutter: utilizando Bitrise, GitHub Actions e Codemagic

Testes no CI com Flutter: utilizando Bitrise, GitHub Actions e Codemagic

Integração contínua com Flutter - Apresentação

Fala, dev! Boas-vindas ao curso de Testes na Integração Contínua com Flutter. Eu sou o Petros Barreto e serei seu instrutor.

Audiodescrição: Petros se autodeclara um homem pardo. Tem cabelo escuro e curto, uma barba escura e cheia contornando seu rosto e olhos castanho-escuros. Veste uma camiseta preta. Ao fundo, um ambiente de iluminação rosa e roxa e uma parede com alguns quadros de decoração.

O que vamos aprender?

Neste curso, vamos aprender sobre:

Pré-requisitos

Para ter o melhor aproveitamento possível deste curso, é necessário que você tenha um conhecimento básico de Flutter e também um conhecimento básico sobre testes.

Nos encontramos na primeira aula!

Integração contínua com Flutter - Integração contínua - Github Actions

Fala, dev! Nesta aula, vamos explorar o funcionamento do nosso aplicativo AnyBank. O repositório deste projeto está disponível no GitHub. Quando você rodar este projeto (com o comando flutter pub get e depois um flutter build ou um flutter run), ele será executado no seu simulador. Com isso, você identificará que ele se assemelha a um aplicativo de banco.

O AnyBank já possui algumas funcionalidades, incluindo o fluxo de transferência, o fluxo de cobrança e toda a página inicial que já foi desenvolvida. Não temos todos os fluxos funcionando, como o de cartões e recarga, mas já temos o suficiente para iniciar a nossa atividade.

Neste curso, gostaríamos que você imaginasse que está trabalhando em um projeto com uma equipe de muitas pessoas, e cada pessoa cuida de um fluxo do projeto. Por exemplo, há um time que cuida especificamente do fluxo de transferência e um time que cuida especificamente do fluxo de cobrança.

Sendo assim, como podemos garantir que quando todos esses times concluírem o desenvolvimento e entregarem todas as suas funcionalidades e correções, tudo funcionará bem quando juntarmos essas peças?

Nas grandes empresas, atualmente, existe um fluxo de Integração Contínua (CI) para garantir esse funcionamento. Mas, em projetos que ainda estão nascendo, algumas empresas não utilizam o fluxo de CI. Nesse caso, elas designam uma pessoa para realizar todo esse processo de juntar as peças, buildar o projeto, gerar os arquivos APK e IPA e enviá-los para a Apple, para o Google e assim por diante.

Utilizando o CI e os testes de integração contínua, adicionamos mais uma etapa nesse fluxo: antes de juntar as peças da aplicação e gerar a versão, criamos testes de forma automática.

Rodando os testes do AnyBank

No nosso curso, vamos utilizar algumas ferramentas - o GitHub Actions, Bitrise e o Codemagic. Neste primeiro caso, vamos fazer um teste utilizando o GitHub Actions.

Para isso, vamos explorar o código do projeto AnyBank, que você terá acesso após baixá-lo do repositório.

Nos arquivos desse projeto, temos uma pasta chamada "test", onde há um arquivo chamado account_test.dart, com alguns testes já criados. Dentre eles, temos um teste chamado Testa uma transferência e outro chamado Testa de ua nova transferência, com um erro de digitação proposital, para verificarmos o resultado disso mais tarde.

Também temos o teste Transferir números negativos, o Transferir qualquer coisa que não seja um número, Transferir 0 e o transferir mais do que disponível no saldo. Todos esses são testes que já criamos para utilizar na integração contínua.

Você pode fazer todo esses testes na sua máquina, antes de enviar para o CI, e garantir que, na sua máquina, a aplicação está rodando corretamente e as funcionalidades estão ok. Então, vamos abrir um terminal para fazer isso.

Com o terminal aberto, vamos rodar o seguinte comando:

flutter test

Ao fazer isso, todos os nossos testes previamente escritos serão executados. Nesse momento, todos devem passar (conforme o retorno All tests passed!), indicando que tudo funciona bem.

Mas, se um desses testes der errado, teremos outro resultado. Por exemplo, se o balance (saldo) da conta é 100, vamos tentar transferir 101 no teste:

acoount.test.dart

test("Testa uma transferência", () {
    final Account account = Account(number: 123, cpf: "322.123.123-22", balance: 100.0, name: "Beto");

    account.transfer(101);

    expect(account.balance, 0);
});

Nesse caso, ao executar o flutter test novamente no terminal, receberemos uma exceção, ou seja, um erro.

Como podemos fazer com que uma alteração de código seja testada? No nosso caso, a identificação da alteração - e, por consequência, do erro - no código não foi automática. Tivemos que fazer uma interação com o terminal, executando o comando flutter test.

Imagine que, em um time com muitas pessoas trabalhando, você fez uma alteração de código que, infelizmente, foi errada - como a que acabamos de fazer no código Testa uma transferência. Mas você esqueceu de testar, então não identificou esse erro, e fez o commit para o CI. como faremos agora, executando seguinte comando no terminal:

git add .

Depois, vamos executar o seguinte comando para consultar as alterações que enviamos para esse commit:

git status

Temols apenas a alteração no account_test.dart, conforme o esperado. Agora vamos enviar essa alteração com a mensagem "erro no teste":

git commit -m "erro no teste"

Por fim, rodamos:

git push

Assim que tudo subir, vamos para o GitHub no navegador. Ao atualizar a página, verificaremos que, quando fizemos o commit, o CI roda automaticamente.

Script para rodar os testes

Existe um arquivo dentro do nosso GitHub que, sempre que fizermos um commit, executa uma série de passos de um script. Ele está numa uma pasta chamada .github/workflows e se chama flutter.yml.

Esse arquivo é um script que diz para o GitHub tudo o que queremos que o GitHub faça, ou seja, quais são os processos que ele deve executar e como ele vai executar cada processo. Podemos adicionar vários processos nesse arquivo, e disponibilizmaos para você este script básico para poder rodar os testes no CI do GitHub.

name: Flutter CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.22.2'

      - name: Install dependencies
        run: flutter pub get

      - name: Run test Petros
        run: flutter test

Primeiramente, nomeamos esse script como Flutter CI e definimos que, sempre que acontecer um push ou um pull_request, uma série de comandos seja executada, definidos na seção jobs (tarefas) desse arquivo.

Pedimos que ele utilize a última versão do Ubuntu na execução desse projeto (runs-on: ubuntu-latest) pois, neste caso, não precisamos de nada do iOS.

Abaixo, em steps, definimos o passo a passo a ser seguido. Primeiramente, pedimos checkout@v4, uma Action ligada ao GitHub. Depois, criamos um novo setup do Flutter, especificando a versão específica que queremos utilizar. Dentre as várias disponíveis, escolhemos a versão 3.22.2, que suporta o nosso projeto.

Vale lembrar que, sempre que você executa um CI, é como se estivesse rodando o projeto em uma máquina nova. Então, você precisa passar a configuração do setup inicial para a máquina antes de tudo. Há a possibilidade de armazenar essas configurações em cache, mas isso depende de cada caso, e não faremos isso agora.

Como próxima etapa, configuramos a instalação das dependências com flutter pub get e, depois, flutter test para rodar os testes (com o nome Run test Petros apenas por ser o nome do instrutor, mas você pode definir o nome que desejar para esse passo).

Voltando para o GitHub, se clicarmos na aba "Actions" no menu superior da tela, verificaremos que o commit "erro no teste", que acabamos de fazer, teve uma falha. Para entender melhor, vamos clicar no commit.

Na tela de detalhes desse commit, vamos clicar em "build" no centro da tela. Feito isso, teremos os logs de execução e poderemos entender o que aconteceu. O momento da falha se deu na execução "Testa uma transferência", justamente onde fizemos a alteração. Isso aconteceu porque tentamos transferir um valor maior do que o disponível no saldo atualmente.

Vamos ajustar isso. De volta ao VS Code, no arquivo account_test.dart vamos voltar a passar 100, o valor máximo de saldo na conta atualmente:

acoount.test.dart

test("Testa uma transferência", () {
    final Account account = Account(number: 123, cpf: "322.123.123-22", balance: 100.0, name: "Beto");

    account.transfer(100);

    expect(account.balance, 0);
});

Vamos salvar o arquivo e executar a seguinte sequência de comandos no terminal, como já sabemos, para enviar o novo commit "teste certo" para o GitHub:

git add .
git status
git commit -m "teste certo"
git push

Assim que tudo subir, vamos voltar para o GitHub. Agora, ao clicar em "Actions", veremos o commit "teste certo" sendo executado em tempo real, com status "pending". Podemos clicar nele e depois em "build" novamente para acompanhar.

Os passos seguidos nessa execução são os mesmos que acabamos de conferir no script flutter.yml. Ou seja, ao final desse processo, ele roda os testes, e os doze passam!

Ao final, o build ficou com um status de sucesso (checkmark verde). Então se precisarmos, no futuro, fazer uma integração que só vai criar um app ou fazer um merge, ou então só vai gerar uma versão para o cliente, por exemplo, e todos os testes que foram criados passarem, podemos fazer essa etapa que acabamos de fazer.

Quando você clica em "Code" no GitHub, no canto superior esquerdo, verificaremos que está tudo ok. Se você criar um pull request com um commit atrelado, ele vai precisar primeiro rodar para aprovar o pull request.

Então, a partir de agora você consegue criar regras para garantir que a qualidade da sua entrega tenha mais sucesso, que todos os testes passem, sem nenhum erro.

Até a próxima aula!

Integração contínua com Flutter - Configurando o ambiente de CI - Bitrise

Fala, dev! Agora vamos falar sobre o Bitrise, uma ferramenta um pouco semelhante ao GitHub Actions. A diferença é que o Bitrise nos proporciona tanto a visão de código quanto a visão de navegação, com um dashboard para gerenciar todo o nosso CI.

O Bitrise é uma ferramenta paga, que oferece 30 dias gratuitos para testar a ferramenta. O Bitrise é uma ferramenta muito utilizada pelas empresas, porque nela temos como escolher uma máquina específica para atender as nossas necessidades.

As outras ferramentas que abordamos e ainda abordaremos nesse curso, o GitHub e o Codemagic, também têm algumas opções adicionais. Porém, você precisa analisar se essas opções vão atender o seu caso. Sempre analise bem antes de escolher a melhor ferramenta para você, conforme as especificações técnicas do seu projeto.

Criando um projeto no Bitrise

Vamos fazer a configuração inicial de um projeto no Bitrise.

Na página inicial, após fazer login, você vai se deparar com dois botões: Bitrise CI e Build Cache. Você pode clicar em Bitrise CI e, na próxima tela, clicar em "New CI project" para criar um novo projeto.

Se você quiser mais informações sobre essa ferramenta e aprender mais sobre como começar com outros tipos de projeto além do Flutter, há vários tutoriais que você pode conferir logo abaixo nessa página de Início.

Na próxima tela, temos a opção de selecionar um Workspace (área de trabalho) para iniciar esse projeto. Você pode ter mais de um Workspace dentro da sua estrutura, por exemplo: uma área para os seus projetos pessoais e outra para os seus projetos de trabalho.

Escolhido o Workspace, vamos clicar em "Next" (próximo). Na próxima tela, teremos a uma opção de integrar o projeto com repositórios de outros lugares, como o GitHub, o Bitbucket, GitLab ou qualquer outra ferramenta de Git. Alternativamente, você pode adicionar manualmente o link do seu repositório, clicando em "Add URL manually".

Recomendamos que você faça a integração direta, porque isso te dá a opção de selecionar o repositório desejado. Para fazer essa integração com o GitHub, por exemplo, você precisa ter o seu acesso SSH configurado no GitHub.

Feito isso, você poderá clicar na opção "GitHub App" como Provider, depois em "Select a repository". Na janela flutuante, selecionamos o repositório do nosso projeto atual, o AnyBank.

Com o projeto selecionado, clicamos em "Next" para avançar. O próprio Bitrise já faz algumas análises e verifica se está tudo ok com esse projeto. Estando tudo ok, vamos escolher a branch padrão para rodar o fluxo. Vamos selecionar a branch main, por exemplo, mas você pode escolher a que você quiser.

Abaixo temos a opção de autodetecção da configuração. Vamos marcar a opção "Yes", para autodetectar a configuração, e clicar em "Next" novamente.

Na próxima etapa, o próprio Bitrise vai fazer uma análise de todo o projeto e nos trazer alguns steps pré-configurados. Diferente do GitHub, que pede para explicarmos o que queremos que ele faça via script, o Bitrise oferece a opção de configurar automaticamente com os passos detectados ou fazer o setup manual.

Vamos marcar a opção "Use detected options" para usar a configuração padrão. Abaixo, vamos escolher o tipo de projeto, entre macOS ou Flutter. Vamos definir como Flutter.

Abaixo, ele pergunta qual é a localização do projeto. Há projetos em que você vai precisar pré-configurar a localização dentro dos arquivos. Se você pegar um projeto que tenha essa especificação, você vai fazer essa configuração. Do contrário, deixamos como padrão.

Na próxima etapa, uma grande vantagem do Bitrise, vamos selecionar a máquina em que vamos rodar esse projeto. Dentre as opções disponíveis de build stack, há várias versões de Xcode e do Ubuntu, e máquinas diversas com várias configurações.

Você pode se perguntar: para que essas configurações todas? Há projetos que só rodam no Xcode 13, por exemplo, e projetos que só rodam no Xcode 10. Isso está muito ligado à versão do SDK, do iOS e assim por diante. Todas essas versões têm suas especificações. Você precisa definir a que melhor vai atender ao seu projeto.

No caso do AnyBank, você pode definir uma configuração padrão. A mais alta que nós temos no momento da gravação desse vídeo é a do Xcode 15.4. Você também pode utilizar uma máquina padrão, que, no momento, é uma máquina M1 com 4 CPUs. Isso vai atender perfeitamente a nossa configuração.

Lembre-se: quanto mais máquina você usa, mais você paga. Em compensação, ela pode rodar o seu projeto mais rápido. Então, você precisa analisar a sua prioridade: um build mais rápido? Ou você quer economizar no tempo de build? Precisamos analisar cada projeto e entender qual a melhor configuração. Para o projeto de curso, a configuração padrão já nos atende.

Vamos clicar em "Next" para avançar. No próximo passo, podemos adicionar um ícone de projeto. No momento, vamos pular essa opção, clicando no botão "Skip for Now". Mas, se quiser, você pode adicionar o ícone do seu app nessa etapa.

Pronto! Todas as configurações foram feitas. Vamos clicar no botão final "View CI Configuration" para visualizar o que vai acontecer.

Execução do fluxo no Bitrise

Imediatamente, o Bitrise roda o primeiro build para saber se tudo deu certo. Aqui, nós temos uma etapa visual: conseguimos ver esse processo de build e execução do workflow acontecendo, com a indicação de cada especificação que configuramos.

Para visualizar o processo em tempo real, clicamos na build em execução no centro da tela. Poderemos acompanhar o processo na aba "Build log". Algumas etapas são seguidas por padrão:

No nosso caso, o Flutter Test passou, porque nós mexemos no código e definimos tudo corretamente para os testes passarem.

Teste falhando no Bitrise

Podemos voltar ao nosso código para fazer o Flutter Test falhar, para visualizar como isso é indicado no Bitrise.

No VS Code, novamente vamos passar 101 em vez de 100 no teste Testa uma transferência:

account_test.dart

test("Testa uma transferência", () {
    final Account account = Account(number: 123, cpf: "322.123.123-22", balance: 100.0, name: "Beto");

    account.transfer(101);

    expect(account.balance, 0);
});

Vamos salvar, abrir o terminal e rodar a seguinte sequência de comandos para enviar a commit "erro teste":

git add .
git status
git commit -m "erro teste"
git push

Vamos retornar ao Bitrise para verificar como é que ele vai se comportar.

Enquanto o Bitrise roda o commit "erro teste", vamos também rodar mais um teste (clicando em "Start build" no canto superior direito) para visualizar como funcionam todos os workflows dentro do Bitrise.

Continua no próximo vídeo...

Sobre o curso Testes no CI com Flutter: utilizando Bitrise, GitHub Actions e Codemagic

O curso Testes no CI com Flutter: utilizando Bitrise, GitHub Actions e Codemagic possui 99 minutos de vídeos, em um total de 44 atividades. Gostou? Conheça nossos outros cursos de Flutter 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 Flutter acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas