https://a.storyblok.com/f/270183/29203/d351dfbbc6/mutation-testing.png

Use o teste de mutação para aprimorar suas habilidades em engenharia de software!

Publicado em October 19, 2023

Tempo de leitura: 23 minutos

A cobertura de código (a porcentagem de código executado durante a execução dos testes) é uma ótima métrica. No entanto, a cobertura não indica o quão eficazes são seus testes na detecção de alterações na sua base de código; simplesmente porque se trata de uma métrica quantitativa. Se seus testes não forem bem projetados, as alterações podem ser aprovadas nos testes unitários, mas causar falhas na produção.

O teste de mutação é uma ótima (e extremamente subestimada) maneira de quantificar o grau de confiança que você pode depositar em seus testes. Os testes de mutação funcionam alterando seu código de maneiras sutis e, em seguida, aplicando seus testes unitários a essas versões “mutadas” do código. Se seus testes falharem, ótimo! Se eles forem aprovados… isso significa que seu teste não foi bom o suficiente para detectar essa alteração.

Neste Video, Max, da equipe de Experiência do Desenvolvedor da Vonage, vai mostrar como começar a fazer testes de mutação em qualquer linguagem de programação e como integrá-los ao seu pipeline de CI/CD. Em breve, detectar código mutante será uma parte rotineira do seu processo de engenharia de lançamento, e você nunca mais vai olhar para os pinguins da mesma forma!

Abaixo está a transcrição do Video, além de alguns links úteis.

Você pode se cadastrar para obter um account gratuito de desenvolvedor na Vonage aqui.

Se você tiver alguma dúvida, entre em contato conosco no nosso Slack da Comunidade.


Olá. Meu nome é Max e sou defensor de desenvolvedores na Vonage. Hoje, gostaria de falar com vocês sobre testes de mutação. Quero explicar como eu os utilizo e como vocês também podem fazê-lo. Antes de começarmos, gostaria de falar brevemente sobre a empresa em que trabalho.

Então, somos uma empresa chamada Vonage e trabalhamos com APIs de comunicação, entre outras coisas. Assim, grande parte do código com o qual trabalho envolve coisas como enviar SMS ou fazer chamadas de voz, criar videochamadas, coisas desse tipo. Ou seja, muitas coisas relacionadas à comunicação. E o motivo pelo qual estou mencionando isso é que, na verdade, apliquei testes de mutação ao nosso código. Quero mostrar a vocês como fiz isso, por que essa foi uma boa escolha para nós e como vocês podem fazer o mesmo. Mas, antes de começar de verdade, quero apresentar o verdadeiro protagonista desta palestra.

Eu sou quem está falando, mas o verdadeiro protagonista, na verdade, é o Henry. Bem, este aqui é o Henry. Espero que vocês possam ver que ele é um pinguinho adorável. E a razão pela qual ele é o personagem realmente importante aqui é que, enquanto eu estava aprendendo sobre testes de mutação para usá-los, eu usava o Henry como analogia para muitas coisas. Vocês vão entender o porquê, pois vou usá-lo também hoje para mostrar como os testes de mutação realmente funcionam. Antes de começarmos, vamos definir alguns pontos de referência.

Então, antes de mais nada, gostaria que vocês refletissem sobre o seguinte: vocês já ouviram falar em testes? Presumo que, se clicaram neste Video, se estão assistindo a ele, provavelmente já sabem o que são testes de software.

Também gostaria que vocês pensassem sobre cobertura de código. Talvez vocês já conheçam o conceito de cobertura de código, talvez não. Não se preocupem se não conhecerem, pois é algo que certamente abordaremos. Há também o teste de mutação. Suponho que você já tenha ouvido falar disso, se viu o título deste Video, mas é algo realmente útil por si só. E espero que, ao final do Video, vocês saibam muito mais sobre testes de mutação e se sintam à vontade para usá-los. Então, se isso lhes parece interessante, vamos continuar!

O que eu gostaria de fazer é apenas estabelecer uma espécie de ponto de partida. Então, antes de mais nada, quero falar sobre testes. Na verdade, é só essa grande questão: por que escrevemos testes de unidade? Quais são as razões que nos levam a escrever testes para o nosso código? Talvez você queira pausar o vídeo e refletir sobre isso por conta própria. Talvez não. Tudo bem também.

Nesse caso, vou mostrar o que acho que isso pode envolver. E aqui está o que eu tenho. Assim, você pode escrevê-los para provar que seu código funciona. Você pode escrevê-los para fins de documentação, a fim de inspirar confiança no seu código, para testes de regressão, para refatoração e também por questões de conformidade.

Então, basicamente, essas são todas as razões que podem te incentivar a escrever um teste de unidade. E é ótimo que tenhamos isso, é ótimo que tenhamos uma maneira de Verify se nosso código funciona. É ótimo que tenhamos uma maneira de documentar e todas essas coisas incríveis. Mas há um pequeno problema aqui também. O problema é que você pode começar com um projeto pequeno, mas esse projeto pode crescer rapidamente, e o que ele faz pode evoluir com o tempo. E então, à medida que você faz refatorações e coisas do tipo, pode deixar de testar partes do código, pode pular seções. Você pode deixar coisas de fora. Você pode acabar não testando mais todo o seu código. E a questão aqui é que, muitas vezes, não monitoramos nossos testes.

Se não monitorarmos nossos testes, não saberemos o que há de errado com o código que temos, porque não temos como testá-lo e não sabemos se os testes vão nos ajudar. Então, espero que possamos perceber qual é o desafio aqui. Gostaria de dizer que a situação melhora porque temos a cobertura de código, certo? E se você não tiver certeza do que é isso, vou explicar rapidamente. Em minhas palavras, é o seguinte: “quanta parte do código-fonte de um programa é executada quando o conjunto de testes é rodado”. É assim que eu explicaria.

Mas vamos deixar de lado a teoria e mostrar a você um exemplo prático disso. Este é um dos SDKs de código aberto que eu mantenho. E, basicamente, é um SDK em Python para fazer chamadas de API para diversas finalidades. Temos uma API que eu ofereço suporte neste SDK, chamada nossa Messages API. E, dentro dela, você pode enviar mensagens por SMS, MMS, WhatsApp, Facebook e coisas do tipo — vários canais diferentes. Peguei o código e executei algumas métricas de cobertura de código nele, para poder ver quais instruções do código eu estava testando e quais estavam faltando. Você pode ver aqui que cobri a maior parte, mas há uma instrução faltando na linha 23, e essa linha é a que me diz: “Ah, na verdade eu não escrevi um teste para isso”.

Nesse caso, eu não tentei esse tipo de autenticação. E isso significa que agora posso ir escrever um teste para isso. Assim, a cobertura de código já melhorou meu código, e isso é incrível! O que mais ela pode fazer?

Na verdade, isso pode te dar uma visão geral de todo o seu projeto e de todas as diferentes instruções nele contidas — basicamente, qual é o nível de cobertura que você tem. Então, é assim que fica no meu caso. E isso parece ótimo. Há um potencial realmente grande aqui porque, em primeiro lugar, permite que você escreva mais testes e testes melhores.

Além disso, é muito fácil e barato medir esses aspectos. Não exige muito recurso computacional apenas executar a cobertura de código e verificar: “o que eu cobri?”. Outra vantagem, na verdade a melhor delas, é que isso mostra o que você não testou e, assim, você percebe: “ei, preciso prestar atenção nisso”. Se eu não confiar nesse código — o que, na verdade, muitas vezes você não deveria —, isso é muito útil. E, assim, a cobertura de código realmente abrange muitas coisas.

Então, na verdade, acho que talvez já tenhamos encerrado por aqui. Muito obrigado. Foi ótimo conversar com você hoje. Nos vemos de novo... só que, na verdade, há algumas coisas que não são tão boas assim nisso.

Bem, antes de mais nada, a cobertura de código pode ser um pouco enganosa. Além disso, ela não garante a qualidade dos seus testes. Então, o que vou fazer é mostrar a vocês um exemplo de um trecho de código em Python bem simples; aqui está. E tudo o que estou fazendo aqui é importar o requests módulo, que é a biblioteca que estou usando.

Então, estou fazendo uma chamada de API com essa biblioteca. Ou seja, tudo o que estou fazendo é enviar uma solicitação GET para uma URL específica, receber a resposta e devolver o JSON dessa resposta ao usuário. E está tudo certo. Está tudo bem. Podemos ver, porém, no próximo slide, na próxima página, o que tenho aqui: um teste para isso.

Na verdade, ele tem 100% de cobertura, mas não é muito útil. Podemos ver aqui que temos algo que chama a API. Mas o que ele realmente faz é chamar a API e depois simplesmente constatar que, se a chamada foi feita, está tudo certo. Portanto, se esse código foi executado, está tudo certo. O que ele não faz, porém, é validar nada do que possa ser retornado.

Podemos receber uma resposta com o código 200. Podemos receber um 400. Podemos receber outra coisa qualquer. Podemos receber algo que não esperamos, e não lidamos com nenhum desses casos. E também não testamos nenhum desses casos. Portanto, na verdade, esse teste não é muito útil para ajudá-lo com isso.

Então, o que eu gostaria de fazer é fazer uma pergunta bem rápida: você já escreveu um trecho de código e, em seguida, criou um teste para ele, não porque esse teste fosse ser útil, mas porque precisava aumentar um pouco a cobertura de código? Eu já fiz isso e muitas pessoas também. Se você nunca fez, ótimo, estou orgulhoso de você, mas, na verdade, a maioria de nós já fez esse tipo de coisa.

O que costuma acontecer com a cobertura de código é que acabamos transformando-a em uma meta, em vez de algo que deveria nos fornecer insights. E esse, na verdade, é um princípio que tem um nome. É algo real e se chama Lei de Goodhart. Não se aplica apenas à cobertura de testes, mas a afirmação é basicamente esta: “Quando uma métrica se torna uma meta, ela deixa de ser uma boa métrica”.

Isso é muito importante, então vou repetir: “Quando uma métrica se torna uma meta, ela deixa de ser uma boa métrica”. O que quero dizer com isso? Bem, o que quero dizer é que pegamos a cobertura de código — que deveria nos dar informações sobre nosso código e nossos testes e como eles funcionam —, mas, na verdade, transformamos isso em um número que nos preocupamos em otimizar.

Então, em vez de pensarmos em criar testes melhores, estamos pensando em otimizar um número, o que não é tão bom assim. Isso levanta algumas questões. Por exemplo: como podemos entender o que nossos testes estão realmente fazendo? Como sabemos se nossos testes são confiáveis? E, na verdade, a melhor forma de expressar isso foi concebida por volta do ano 100 d.C. pelo pensador romano Juvenal (depois de um quarto copo de vinho), e a frase que ele criou foi “Quem vigia os vigilantes?”. Quem está cuidando das pessoas que deveriam estar cuidando de nós? E, da mesma forma, quem está testando nossos testes?

Hoje vou dar uma resposta para vocês, e afirmo que essa resposta é o teste de mutações. Então, talvez vocês tenham percebido que o Henry voltou a aparecer um pouco.

E isso é incrível porque, em primeiro lugar, ele é adorável, mas, mais importante ainda, ele vai nos ajudar agora. Então, no ano passado, quando comecei a aprender sobre testes de mutação, fiquei pensando muito em como poderia aplicar isso ao meu código e em maneiras de conceituar e entender isso por conta própria. E o que fiz foi imaginar que meu código — que basicamente envia muitas chamadas de API e lida com chamadas de API e mensagens — fosse como um pombo ou uma pomba, como um pássaro que pode voar. Então, o que posso fazer nessa analogia é amarrar uma mensagem na perna do pássaro e soltá-lo; ele vai voar para longe e entregar minha mensagem.

Então ele vai voar e fazer o que eu preciso que ele faça. Agora, o problema com os pinguins é que eles são pássaros, então se encaixam nesse critério, mas não conseguem voar — como você bem sabe, eles não conseguem voar —, e isso os deixa meio irritados. Mas, mais importante ainda, um mutante desse tipo é como uma ave comum transformada em pinguim, que agora não consegue fazer aquilo que mais preciso, que é a ave voar. Vamos ver um exemplo real usando fotos de aves, porque é isso que estamos fazendo hoje.

Primeiramente, começamos com um código de produção, que funciona conforme o esperado. Em seguida, realizamos uma espécie de operação de mutação e criamos uma versão mutante desse código. Temos, por exemplo, esta função, que está em Python. Ela simplesmente soma dois números e retorna a soma desses dois números. Agora, uma versão mutante dessa função poderia, por exemplo, subtrair números, somar uma constante ou retornar a soma de duas strings — coisas desse tipo.

Pode não retornar nada, ou qualquer um dos tipos de operação lógica capazes de alterar o que essa linha de código retorna. Então, o que fazemos com os testes de mutação? Criamos alguns mutantes; o que fazemos a seguir?

Bem, pego os mutantes que temos. Chamo-os de “Fab 4” por motivos que devem ser óbvios, e, basicamente, o que precisamos fazer é submetê-los ao nosso conjunto de testes. Então, pegamos cada mutante. E o que estamos fazendo, basicamente, nessa analogia, é verificar se esse mutante consegue voar, se consegue passar no teste necessário para poder voar para longe e levar essa mensagem. Então, Henry, nosso lindo pinguim mutante aqui, precisa tentar voar.

Então, quando pegarmos esse mutante, vamos rodar nossas suítes de testes. E, na melhor das hipóteses, nossos testes vão falhar. Isso é bom porque significa que revelamos quem o Henry realmente é: um pinguim adorável, o que é incrível, pois significa que, na verdade, não vamos deixá-lo ir para produção. Nós o detectamos em nossos testes. Agora, se os testes forem aprovados, isso é ruim, porque o que aconteceu foi que, na verdade, não percebemos que o Henry é um pinguim e não um pombo.

E ele consegue voar. Quer dizer, olha só essas asas... esse pinguim consegue levantar um ônibus, né? Muito impressionante. Mas isso significa que esse mutante poderia entrar em produção, e é exatamente isso que não queremos. Então, o que isso nos traz?

E afirmo que isso nos proporciona uma maneira de avaliar a qualidade dos nossos testes. É isso que é o teste de mutação.

Vamos falar sobre algumas estruturas que talvez você queira considerar. Bem, no que diz respeito a estruturas, há várias opções para diversas linguagens; você sabe, toda linguagem tem alguma versão disso. No meu caso, eu uso o mutmut, que é uma estrutura de teste de mutação baseada em Python.

Mas se você estiver interessado em outras linguagens, existem ferramentas como o Pitest para Java ou o Stryker para JavaScript, C# e outras semelhantes. Portanto, há opções para várias linguagens. E se a linguagem não tiver sido mencionada, provavelmente ainda há algo disponível para ela. Agora, não sou médico profissional, consultor financeiro, professor nem nada do tipo — o valor do seu investimento pode tanto subir quanto descer. Mas o mais importante para mim é que vou falar sobre o que eu mesmo usei.

Então, hoje vou falar sobre o mutmut, porque foi isso que eu mesmo usei. O que fiz foi aplicar esse teste de mutação ao meu próprio SDK, e vou mostrar a vocês como fiz isso agora mesmo. Primeiro, eu pip install mutmut, que é apenas uma maneira “Pythônica” de instalar coisas, e depois executo o comando. Foi só isso.

Felizmente, ele vem com algumas configurações padrão sensatas, que eu não precisei alterar. Talvez você precise ajustar esses valores, dependendo do que estiver fazendo. Existem várias opções de configuração à sua escolha, mas, no meu caso, isso já estava bom. E quando executei isso, o que aconteceu foi que o programa basicamente me informou o que iria ocorrer. Então, ele exibiu isso.

Ele exibiu a mensagem de que iria executar todo o conjunto de testes, em primeiro lugar, para entender o tempo de execução e coisas do tipo. Em seguida, geraria as variantes e as verificaria. Portanto, há alguns resultados diferentes que podem surgir aqui. Por exemplo, podemos detectar uma variante, podemos ter uma variante que ultrapasse o tempo limite — o que não é bom —, podemos ter variantes que pareçam suspeitas e nas quais talvez não confiemos, e também podemos ter variantes que tenham sobrevivido. E, nesse caso, essa é uma situação realmente ruim, pois sabemos que não detectamos essa variante. Então, quando executei isso, o que vimos, em primeiro lugar, foi que ele rodou meu conjunto de testes e, em seguida, verificou esses mutantes e constatou que eu havia detectado 512 deles, mas não havia detectado 170. Agora, pensem nisso.

Esse número é bom ou ruim? Falaremos sobre isso mais tarde, mas, por enquanto, vamos dar uma olhada em alguns mutantes. Então, aqui está um bem simples que conseguimos detectar. Começamos por aqui. Esta é a nossa classe Messages API.

Temos alguns canais de mensagem válidos pelos quais podemos enviar mensagens. E o mutante acabou de alterar um deles. Ele simplesmente alterou uma das sequências de caracteres. Então, na verdade, não conseguimos mais enviar mensagens por SMS. E, quando fizemos um teste para verificar isso, ele falhou, o que é ótimo.

Isso significa que chamamos isso assim. Aqui está outro exemplo. Não sei se as pessoas que estão assistindo a isso já usaram o Pydantic, mas o Pydantic é uma ótima biblioteca de validação, e nós a usamos no SDK. Aqui está um exemplo em que temos um validador — este é o Pydantic V1 — que arredonda um número para cima. Mas a versão modificada removeu essa anotação, esse decorador (dependendo da sua linguagem, você pode chamá-lo de outra forma; em Python, chamamos de decoradores).

Então, removemos isso. E isso significava, na verdade, que esse código nunca seria chamado; assim, quando eu fazia um teste para arredondar um número, ele nunca era chamado. E, assim, isso também falhou. Isso é bom porque significa que existem duas versões da base de código, dois pequenos “Henries” que conseguimos identificar e dizer: “Ei, você é um pinguim”, que é exatamente o que precisamos.

Então, como podemos ver os mutantes? Bem, se você mutmut show, ele pode te mostrar uma lista deles. E você pode, por exemplo, digitar “1”, como “mostrar número 1”, para exibir o primeiro mutante e ver isso. Então, no nosso caso, o número um aqui, por exemplo, altera o tipo de autenticação e, claro, esse foi fácil de identificar. Mas o que é realmente interessante é que podemos ver os resultados de todos esses testes.

Então, temos um relatório no formato HTML. Dependendo do seu idioma e do software de teste de mutações que você estiver usando, isso pode ser mais ou menos fácil de fazer. Para nós, a interface é bem simples, mas, basicamente, o que ela faz é mostrar todas as mutações que você não detectou em cada arquivo. Então, vamos dar uma olhada em algumas delas.

Aqui está o Mutante 58, que não detectamos, e você vai ver que nem todos eles são iguais. Então, nesse mutante, como você pode ver, tudo o que fizemos foi renomear o logger. E acho que esse registro está fora do escopo dos meus testes. Por isso, na minha opinião, não me importo que esse mutante tenha passado; tudo bem, porque não acho que seja isso que eu deva testar.

Então, tudo bem. Aqui vai outro exemplo. Este é o Mutant 62. E aqui dentro, tudo o que fazemos é alterar o valor de uma constante. E, mais uma vez, não acho que isso esteja dentro do escopo do que quero testar.

Não acho que seja importante para mim verificar se um valor padrão está definido ou não. Isso não é importante para mim neste contexto. Mas vamos dar uma olhada em um que seja mais importante, com o qual eu realmente me importo. Então, aqui está um. Este é o Mutante 112.

E o que estou fazendo aqui é criar instâncias de todas as classes para todas as APIs que usamos. Você pode ver aqui que temos uma classe `Voice`. Na versão “mutante”, não criamos uma classe “Voice”, mas nossos testes ainda são aprovados, mesmo sem criarmos uma classe para todos os nossos métodos de voz. Então, por que isso está acontecendo?

Por que meus testes não estão falhando? O que está acontecendo? Bem, acontece que a forma como usamos isso e como testamos no SDK é que, na verdade, não chamamos apenas por meio dos objetos do cliente. Na verdade, chamamos a classe da Voice API diretamente, mas nossos usuários vão chamá-la assim. E, portanto, provavelmente eu deveria ter um teste para isso.

Então, isso me revela algo muito importante sobre meu código que vai melhorar a qualidade dos testes, pois posso escrever um teste para exatamente esse caso, que é representativo do que nossos usuários farão. Então, vamos voltar a esse número. Conseguimos detectar muitos casos anômalos. Mas também deixamos de detectar alguns. Na verdade, detectamos apenas cerca de 75% desses casos anômalos.

Na verdade, ficamos aquém em cerca de 25%. E a pergunta que tenho para vocês é: esse número é bom? 75%. Isso é bom? E se você estiver assistindo a isso e der de ombros, essa é a resposta certa.

O que é interessante aqui é que 100% não faz sentido! Porque há casos com os quais eu simplesmente não me importo, certo? Como o logger ou aquela constante que muda. Não me importo com isso. Não estou usando isso para obter 100% de cobertura de mutação, porque, nesse caso, tudo o que fiz foi pegar o problema da pontuação de cobertura de código e abstraí-lo novamente. O que realmente me importa é ter uma boa compreensão do meu código, é com isso que realmente me preocupo.

Espero ter convencido vocês de que talvez valha a pena explorar um pouco por conta própria os testes de mutação. Espero mesmo que sim. Mas, se não consegui, não se preocupe, porque o que vou fazer agora é mostrar como você pode começar a fazer testes de mutação, e é tão simples que, na verdade, acho que qualquer pessoa que já escreva testes poderia fazer isso. Antes de mais nada, um conselho geral: comece localmente, execute primeiro na sua máquina. Foi o que eu fiz. Simplesmente executei localmente na minha máquina. Comece aos poucos. Se você tiver uma base de testes maior do que a minha, se tiver um conjunto maior de testes, talvez seja melhor começar com um subconjunto deles. Você também pode querer ajustar o desempenho. Portanto, talvez seja melhor excluir testes específicos que não sejam relevantes para você. Por exemplo, coisas como testes de integração — talvez você não se importe tanto com eles.

Como alternativa, talvez você queira excluir partes do código; por exemplo, se você gerou algum código automaticamente, provavelmente não se importa com ele.

Tudo bem. Então, quando você quiser rodar isso no seu computador — o que é bem provável que aconteça —, essa parte vai te ajudar bastante. Antes de mais nada, estou muito feliz com essa imagem do pinguim. Não sei por que ela existe dessa forma, mas estou muito feliz que exista.

Mas por que você iria querer executar os testes na sua própria máquina? Vou te explicar. Os testes levam algum tempo. Talvez seja melhor usar os recursos da nuvem em vez de usar sua própria máquina sempre que quiser executar um conjunto de testes. Isso também significa que você pode integrá-lo ao seu sistema de CI, o que é muito útil.

Isso significa que você pode especificar diferentes plataformas nas quais deseja executar o código, diferentes sistemas operacionais, diferentes versões da sua linguagem de programação e diferentes versões do seu código. Então, deixe-me mostrar isso para você. Já expliquei por que isso pode ser uma vantagem. Agora, vou apenas mostrar o que fiz e como fiz.

Apliquei isso ao meu SDK do Python. E o que fiz aqui foi criar uma ação no GitHub. Você pode fazer isso em qualquer sistema de CI que preferir. Eu uso o GitHub Actions. Criei algo para testes de mutação — um arquivo YAML muito, muito simples. Basicamente, o que ele faz é me permitir escolher manualmente se quero executar o teste de mutação para meu conjunto de testes. E, na verdade, foi uma escolha minha executá-lo manualmente.

Não quero que ele seja executado automaticamente. Daria para configurá-lo para ser executado ao enviar dados, mas optei por não fazer isso. Então, quando eu executar isso, você vai ver que o que ele vai fazer é, na verdade, apenas concluir essa tarefa. E o que ele também fará é me fornecer esse relatório em HTML. Ele me fornecerá isso como um artefato de execução que posso baixar e, dessa forma, posso ver exatamente como meus testes estão se saindo e quais “mutantes” não estão sendo detectados.

Então, como faço isso? Bem, essa é realmente a questão interessante aqui. Vou mostrar a vocês o YAML que usei. Então, repito, uso o GitHub Actions. É o que eu mesmo uso, mas vocês podem fazer isso em qualquer sistema de CI que preferirem — é só um script simples. E, sinceramente, o que eu também diria é: fiquem à vontade para acessar o SDK que estou mantendo. O código está lá. Você pode pegar o arquivo YAML. E, por favor, use-o você mesmo, fique à vontade. Se isso ajudar você a começar com testes de mutação, todo mundo sai ganhando. Mas, de qualquer forma, vou mostrar o YAML agora mesmo. Vou explicar o que cada parte faz e como funciona.

Em primeiro lugar, dá para ver aqui que temos um arquivo YAML para o teste de mutação. Dá para ver que estamos rodando no Ubuntu. Estamos usando apenas uma versão do Python. Tudo bem. Podemos ver aqui as diferentes etapas. Então, fazemos o check-out do código e, em seguida, configuramos o Python.

Depois de fazer isso, instalamos nossas dependências, mas agora incluímos a dependência mutmut. Depois de fazer isso, executamos nosso teste de mutação, o que fazemos com mutmut run, e usamos duas opções ali. Usamos --no-progress, o que basicamente significa que nossas saídas ficam mais legíveis quando as lemos de volta em nosso sistema de CI. E também usamos o --CI modo, que nos retorna um código de erro significativo. Vou destacar isso porque foi minha única contribuição para mutmut, mas ainda tenho orgulho disso, então vou mencionar. Na verdade, é muito útil aqui, porque, do contrário, não recebemos um código de erro significativo e isso faz com que o GitHub Actions falhe. Depois de fazer isso, obtemos essa saída em HTML e a enviamos para que possamos baixá-la do GitHub mais tarde. E é isso. São 35 linhas, é tudo o que fazemos, e está tudo certo.

Que outras preocupações temos em relação ao CI? Sobre que outros aspectos vocês gostariam de refletir? Bem, antes de mais nada, é importante pensar na diferença entre acionamento manual e automático. Pessoalmente, prefiro executar essas tarefas manualmente, pois não quero que isso faça parte de um processo de PR em que seja necessário atingir uma determinada pontuação para ser aprovado.

Quero executar isso quando tiver adicionado algo novo que possa alterar o funcionamento ou se precisar de uma análise do meu código. Você pode executá-lo automaticamente, se quiser, mas saiba que não é obrigatório. Não queremos simplesmente abstrair a Lei de Goodhart novamente e tentar transformar a pontuação de mutação em uma nova métrica a ser abstraída. Também queremos pensar na possibilidade de executar o código em vários sistemas operacionais. No meu caso, não precisei fazer isso porque não espero que haja mudanças significativas — não mexemos no sistema operacional. Estamos mais focados em chamadas de API, então isso não é um grande problema para nós. Você também pode querer executar com várias versões de suas dependências e coisas do tipo, para ver se alguma coisa muda para você também.

Resumindo, o teste de mutação testa os seus próprios testes. Ele ajuda a superar a Lei de Goodhart no que diz respeito à cobertura de código. Se você quiser usá-los, eu diria para começar em pequena escala e localmente, mas, quando estiver pronto, execute-os em um sistema de CI para que você possa fazer isso de forma assíncrona e não desperdice o tempo e os recursos da sua máquina. Por fim, só quero dizer que os mutantes são valiosos e também maravilhosos. Se pensarmos no Henry e em tudo o que ele nos proporcionou — tipo, tudo bem, ele não consegue voar, não consegue fazer o trabalho que precisamos do código —, mas o que ele fez nos deu tanta percepção sobre nossa base de código que ele é simplesmente maravilhoso. E, assim como disse no início desta apresentação, vocês não devem temer os “mutantes”, porque devem amá-los.

Muito obrigado. Foi realmente muito bom conversar com você hoje. Se quiser entrar em contato comigo para tirar alguma dúvida, por favor, participe do Slack da Comunidade Vonage. Se quiser conhecer o SDK do Python, fique à vontade para dar uma olhada nele também. E se você quiser criar um Account na Vonage e experimentar nossos produtos, mais uma vez, há um link aqui também.

Espero que essas dicas sejam úteis para vocês. Muito obrigado e até a próxima. Um abraço.

Compartilhar:

https://a.storyblok.com/f/270183/400x400/92109caf6a/max-kahan.png
Max KahanEx-funcionários da Vonage

Max é um ex-membro da equipe da Vonage. Ele atuou como Promotor de Desenvolvedores Python e Engenheiro de Software, com interesse em APIs de comunicação, aprendizado de máquina, experiência do desenvolvedor e dança! Ele é formado em Física, mas atualmente trabalha em projetos de código aberto e cria soluções para facilitar a vida dos desenvolvedores.