Introdução ao Python (26) Teste (1)

1. Visão Geral

Quando você escreve uma função ou classe, também pode escrever testes para ela. O teste garante que o código funcione conforme o esperado para várias entradas. O teste nos dá confiança de que seu programa funcionará corretamente, mesmo que mais pessoas o usem. Ao adicionar um novo código ao seu programa, você também pode testá-lo para garantir que não quebre o comportamento existente do programa. Os programadores cometem erros, portanto, todo programador deve testar seu código com frequência para detectar problemas antes que os usuários os percebam.

Portanto, aprenderemos como usar as ferramentas do teste de unidade do módulo Python para testar o código e também aprenderemos a escrever casos de teste que verificam se uma série de entradas produzirá a saída esperada. Veremos como é passar em um teste, como é falhar em um teste e como a falha em um teste pode ajudar a melhorar o código. Aprenda a testar funções e classes e saiba quantos testes escrever para seu projeto.

2. Função de teste

Para aprender a testar, você deve ter código para testar. Aqui está uma função simples que pega um nome e um sobrenome e retorna o nome arrumado:

def get_formatted_name(first, last):
    """生成整洁的姓名。"""
    full_name = f"{
      
      first} {
      
      last}"
    return full_name.title()

A função get_formatted_name() combina o nome e o sobrenome em um nome: coloque um espaço entre o nome e o sobrenome, coloque a primeira letra em maiúscula e retorne o resultado. Para verificar se get_formatted_name() funciona como esperado, vamos escrever um programa que use esta função. O programa names.py permite que o usuário digite um nome e sobrenome e exibe os nomes de forma organizada:

from name_function import get_formatted_name

print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name: ")
    if first == 'q':
        break
    last = input("Please give me a last name: ")
    if last == 'q':
        break

    formatted_name = get_formatted_name(first, last)
    print(f"\tNeatly formatted name: {
      
      formatted_name}.")

Este programa importa get_formatted_name() de name_function.py. Os usuários podem inserir uma série de nomes e sobrenomes e ver os nomes bem formatados:

Enter 'q' at any time to quit.

Please give me a first name: janis
Please give me a last name: joplin
        Neatly formatted name: Janis Joplin.

Please give me a first name: bob
Please give me a last name: dylan
        Neatly formatted name: Bob Dylan.

Please give me a first name: q

Na saída acima, podemos ver que o nome mesclado está correto. Agora suponha que você queira modificar get_formatted_name() para também lidar com nomes do meio. Ao fazer isso, certifique-se de não interromper a maneira como essa função lida com nomes apenas com nomes e sobrenomes. Para fazer isso, teste após cada modificação de get_formatted_name(): execute o programa names.py e insira um nome como Janis Joplin. Mas isso é muito complicado. Felizmente, o Python fornece uma maneira eficiente de testar automaticamente a saída das funções. Se você automatizar o teste de get_formatted_name(), sempre poderá ter certeza de que a função funcionará corretamente quando fornecida com o nome testado.

2.1 Testes de unidade e casos de teste

O módulo unittest na biblioteca padrão do Python fornece ferramentas de teste de código. Os testes de unidade são usados ​​para verificar se um determinado aspecto de uma função está correto. Um caso de teste é um conjunto de testes de unidade que juntos verificam se uma função se comporta conforme o esperado em várias circunstâncias. Um bom caso de teste considera as várias entradas que uma função pode receber e inclui testes para todas essas situações. Os casos de teste totalmente cobertos incluem um conjunto completo de testes de unidade que cobrem todos os usos possíveis da função. Para grandes projetos, pode ser difícil testar com cobertura total. Normalmente, é suficiente escrever testes para comportamentos importantes do código primeiro e, em seguida, considerar a cobertura completa quando o projeto é amplamente utilizado.

2.2 Testes passáveis

Demora um pouco para se acostumar com a sintaxe para criar casos de teste, mas depois que os casos de teste são criados, é fácil adicionar testes de unidade para funções. Para escrever casos de teste para uma função, primeiro importe o módulo unittest e a função a ser testada, depois crie uma classe que herde unittest.TestCase e escreva uma série de métodos para testar diferentes aspectos do comportamento da função.

O caso de teste a seguir contém apenas um método, que verifica se a função get_formatted_name() funciona corretamente quando recebe um nome e um sobrenome:

  import unittest
  from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
      """测试name_function.py。"""

      def test_first_last_name(self):
          """能够正确地处理像Janis Joplin这样的姓名吗?"""
❷         formatted_name = get_formatted_name('janis', 'joplin')
❸         self.assertEqual(formatted_name, 'Janis Joplin')
if __name__ == '__main__':
      unittest.main()

Primeiro, o módulo unittest e a função get_formatted_name() a serem testados são importados. Em ❶, uma classe chamada NamesTestCase é criada para conter uma série de testes de unidade para get_formatted_name(). A classe pode ter o nome que você quiser, mas é melhor fazer com que ela pareça estar relacionada à função a ser testada e incluir a palavra Teste. Essa classe deve estender a classe unittest.TestCase para que o Python saiba como executar os testes que você escreve.

NamesTestCase contém apenas um método para testar um aspecto de get_formatted_name(). Nomeie o método test_first_last_name() porque você deseja verificar se um nome com apenas nomes e sobrenomes está formatado corretamente. Ao executar test_name_function.py, todos os métodos iniciados com test_ serão executados automaticamente. Neste método, a função a ser testada é chamada. Neste exemplo, get_formatted_name() é chamado com os argumentos 'janis' e 'joplin', e o resultado é atribuído à variável formatted_name (consulte ❷).

Em ❸, um dos recursos mais úteis da classe unittest é usado: o método assert. Os métodos de assertividade verificam se o resultado obtido é consistente com o resultado esperado. Aqui, sabemos que get_formatted_name() deve retornar nomes com primeiro e último maiúsculos com um espaço entre eles, então esperamos que o valor de formatted_name seja JanisJoplin. Para verificar se este é realmente o caso, chamamos o método assertEqual() do teste unitário, passando a ele o nome_formatado e 'Janis Joplin'. linha de código.

self.assertEqual(formatted_name, 'Janis Joplin')

significa: "Compare o valor de formatted_name com a string 'Janis Joplin'. Se forem iguais, você está pronto; se não forem, me avise!"

Executaremos esse arquivo diretamente, mas deve-se observar que muitos frameworks de teste primeiro importam o arquivo de teste e depois o executam. Ao importar um arquivo, o interpretador irá executá-lo conforme for importado. O bloco if em ❹ verifica a variável especial __name__, que é definida no momento da execução do programa. Se este arquivo for executado como o programa principal, a variável __name__ será definida como ' main '. Aqui, unittest.main() é chamado para executar o caso de teste. Se este arquivo for importado pelo framework de testes, a variável __name__ terá um valor diferente de ' main ', então unittest.main() não será chamado.

Quando executo test_name_function.py, obtenho a seguinte saída:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Um ponto na primeira linha indica que um teste foi aprovado. A próxima linha indica que o Python executou um teste que levou menos de 0,001 segundos. OK no final indica que todos os testes de unidade neste caso de teste foram aprovados.

A saída acima mostra que a função get_formatted_name() sempre lida com isso corretamente quando recebe um nome que contém um nome e um sobrenome. Depois de modificar get_formatted_name(), o caso de teste pode ser executado novamente. Se passar, significa que, dado um nome como Janis Joplin, a função ainda o trata corretamente.

2.3 Testes falhados

O que acontece quando o teste falha? Vamos modificar get_formatted_name() para que ele possa lidar com nomes do meio, mas ao mesmo tempo deliberadamente tornar a função incapaz de lidar corretamente com nomes e sobrenomes como Janis Joplin.

Aqui está uma nova versão da função get_formatted_name() que requer que um nome do meio seja especificado por meio de um argumento:

def get_formatted_name(first, middle, last):
    """生成整洁的姓名。"""
    full_name = f"{
      
      first} {
      
      middle} {
      
      last}"
    return full_name.title()

Esta versão deve lidar corretamente com nomes que incluem um nome do meio, mas ao testá-la, descobrimos que ela não lida mais corretamente com nomes apenas com nome e sobrenome. Ao executar o programa test_name_function.py desta vez, a saída é a seguinte:

❶ E
  ======================================================================
❷ ERROR: test_first_last_name (__main__.NamesTestCase)
  ----------------------------------------------------------------------
❸ Traceback (most recent call last):
    File "test_name_function.py", line 8, in test_first_last_name
      formatted_name = get_formatted_name('janis', 'joplin')
  TypeError: get_formatted_name() missing 1 required positional argument: 'last'

  ----------------------------------------------------------------------
❹ Ran 1 test in 0.000s

❺ FAILED (errors=1)

Há muitas informações lá, porque pode haver muitas coisas que precisam ser conhecidas quando um teste falha. A primeira linha da saída tem apenas uma letra E (consulte ❶), indicando que um teste de unidade no caso de teste causou um erro. Em seguida, vemos que test_first_last_name() em NamesTestCase causa um erro (consulte ❷). Quando um caso de teste contém muitos testes de unidade, é crucial saber qual teste falhou. Em ❸ vemos um traceback padrão indicando que há um problema com a chamada de função get_formatted_name('janis', 'joplin') porque um argumento posicional essencial está ausente.

Também vemos um teste de unidade sendo executado (consulte ❹). Finalmente, uma mensagem informando que todo o caso de teste falhou porque ocorreu um erro ao executá-lo (consulte ❺). Esta mensagem está no final da saída para que você possa vê-la rapidamente. Você não quer ter que percorrer uma longa saída para descobrir quantos testes falharam.

2.4 O que fazer se o teste falhar

E se o teste falhar? Se as condições verificadas estiverem corretas, passar no teste significa que a função se comporta corretamente e falhar no teste significa que o novo código escrito está errado. Portanto, quando um teste falhar, em vez de modificá-lo, corrija o código que causou a falha do teste: examine as alterações que acabaram de ser feitas na função e encontre as alterações que fizeram com que a função se comportasse de maneira diferente do esperado.

Neste exemplo, get_formatted_name() exigia anteriormente apenas dois argumentos, primeiro e último, mas agora requer primeiro, nome do meio e sobrenome. O novo parâmetro de nome do meio era obrigatório, o que fazia com que get_formatted_name() se comportasse de forma inesperada. A melhor opção aqui é tornar o nome do meio opcional. Depois de fazer isso, o teste passa novamente quando testado com um nome semelhante a Janis Joplin, e nomes do meio também são aceitos. Vamos modificar get_formatted_name() para tornar o nome do meio opcional e executar o caso de teste novamente. Se for aprovado, prossiga para verificar se a função lida com nomes do meio corretamente.

Para tornar o nome do meio opcional, mova o parâmetro formal middle para o final da lista de parâmetros formais na definição da função e atribua seu valor padrão a uma string vazia. Você também precisa adicionar um teste if para que os nomes sejam criados de acordo, dependendo se um nome do meio é fornecido:

def get_formatted_name(first, last, middle=''):
    """生成整洁的姓名。"""
    if middle:
        full_name = f"{
      
      first} {
      
      middle} {
      
      last}"
    else:
        full_name = f"{
      
      first} {
      
      last}"
    return full_name.title()

Nesta nova versão de get_formatted_name(), o nome do meio é opcional. Se um nome do meio for passado para a função, o nome consistirá em primeiro nome, nome do meio e sobrenome, caso contrário, nome consistirá apenas em nome e sobrenome. Agora, a função deve manipular os dois nomes diferentes corretamente. Para garantir que a função ainda manipule nomes como Janis Joplin corretamente, vamos executá-la novamente.

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Agora, o caso de teste passa. Isso é ótimo, significa que a função funciona corretamente com nomes como Janis Joplin novamente e não precisamos testar a função manualmente. A razão pela qual esta função é fácil de corrigir é porque o teste com falha nos permite saber que o novo código quebra o comportamento original da função.

2.5 Adicionando novos testes

Assim que tivermos certeza de que get_formatted_name() lida com nomes simples corretamente novamente, vamos escrever um teste para nomes que incluam nomes do meio. Para fazer isso, adicione mais um método à classe NamesTestCase:

  --snip--
  class NamesTestCase(unittest.TestCase):
      """测试name_function.py。"""

      def test_first_last_name(self):
          --snip--

      def test_first_last_middle_name(self):
          """能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""
❶         formatted_name = get_formatted_name(
              'wolfgang', 'mozart', 'amadeus')
          self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')

  if __name__ == '__main__':
      unittest.main()

Nomeie o método test_first_last_middle_name(). O nome do método deve começar com test_ para que seja executado automaticamente quando executarmos test_name_function.py. O nome do método indica claramente qual comportamento de get_formatted_name() ele testa. Dessa forma, se o teste falhar, saberemos imediatamente qual tipo de nome foi afetado. Você pode usar nomes de método muito longos na classe TestCase, e esses nomes de método devem ser descritivos para que você possa entender a saída quando o teste falhar. Esses métodos são chamados automaticamente pelo Python, você não precisa escrever nenhum código para chamá-los.

Para testar a função get_formatted_name(), nós a chamamos com o nome, sobrenome e nome do meio (consulte ❶) e, em seguida, usamos assertEqual() para verificar se o nome retornado corresponde ao nome esperado (primeiro, meio e sobrenome). Ao executar test_name_function.py novamente, ambos os testes passam:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Acho que você gosta

Origin blog.csdn.net/qq_41600018/article/details/131333194
Recomendado
Clasificación