1 of 26

Exceções e Testes

2 of 26

Programas podem ser mais amigáveis

  • Digite um número: abc
  • Isso não é um número válido
  • Digite um número: 23a
  • Isso não é um número válido
  • Digite um número: *
  • Isso não é um número válido
  • Digite um número: 123
  • Ok!

3 of 26

Exemplo 1 (errado)

  • Criando uma função para ler números inteiros:

1ª Versão:

def ler_int(mensagem, mensagem_de_erro):

entrada = int(input(mensagem))

return entrada

# programa principal

MSG = 'Digite um número inteiro'

MSG_ERRO = 'Número inválido'

x = ler_int(MSG, MSG_ERRO)

y = ler_int(MSG, MSG_ERRO)

print(x + y)

4 of 26

try .. except

  • Usar uma estrutura de controle de tratamento de erro:

try:

commandos que podem causar erro

except ErroConhecido:

commandos que são executados se o erro ocorrer

5 of 26

Exemplo 1: try .. except na prática

  • Criando uma função para ler números inteiros:

2ª Versão:

def ler_int(mensagem, mensagem_de_erro):

while True:

try:

entrada = int(input(mensagem))

return entrada

except:

print(mensagem_de_erro)

# programa principal

MSG = 'Digite um número inteiro'

MSG_ERRO = 'Número inválido'

x = ler_int(MSG, MSG_ERRO)

y = ler_int(MSG, MSG_ERRO)

print(x + y)

6 of 26

Exemplo 2: divisão de inteiros

def divisão(x, y):

try:

return x/y

except ZeroDivisionError:

return None

print(divisão(12, 10))

print(divisão(3, 1))

print(divisão(14, 0))

# Por que testar?

Entradas

Saída

x

y

divisão

12

10

1.2

3

1

3

14

0

None

7 of 26

Por que TESTAR?

8 of 26

Por que fazer testes?

UEFS - UNIVERSIDADE ESTADUAL DE FEIRA DE SANTANA

8

9 of 26

Por que testar?

  • [Portal de notícias ClicRBS]

10 of 26

Bugs e Testes

  • Bugs são inevitáveis em qualquer software complexo.
    • Estimativas da indústria: 10-50 bugs por 1000 linhas de código.
    • Um bug pode ser visível ou pode se esconder em seu código até bem mais tarde.

  • Testes: Tentativa sistemática de revelar erros.
    • Teste falhou: um erro foi demonstrado.
    • Teste passou: erros não foram encontrados (nesta situação particular).

11 of 26

Exemplo 2b: Uma maneira mais elegante de testar

def divisão(x, y):

try:

return x/y

except ZeroDivisionError:

return None

assert divisão(12, 10) == 1.2

assert divisão(3, 1) == 3

assert not divisão(14, 0)

print('Todos os testes passando!')

Entradas

Saída

x

y

divisão

12

10

1.2

3

1

3

14

0

None

12 of 26

  • O comando assert (traduz-se como asserção ou afirmação) é uma maneira simples e elegante de testar código
  • Se uma asserção é verdadeira, nada acontece (o código está correto)
  • Se uma asserção é falsa, há erro no código, evidenciado pela asserção
  • A forma do assert padrão é:

assert condição_lógica

Asserções em Python

13 of 26

Desenvolvimento dirigido por testes

  • Testes podem ser escritos depois, durante ou mesmo antes de codificar.
    • test-driven development (TDD): escreva os testes, só depois escreva o código para passar nos testes.
  • Escreva o código para testar o programa antes que ele tenha sido escrito.
    • Então, assim que implementarmos o programa, saberemos se ele funciona.
  • Processo do TDD:
    1. Escreva um teste.
    2. Rode o teste e veja se passa ou falha.
    3. Se falhar, faça algum código para o teste passar.
    4. Faça mais testes, repetindo os passos 1 a 3 até sentir confiança de que o programa está ‘correto’.
    5. Refatore o código para deixá-lo mais eficiente ou elegante.

14 of 26

Exemplo 3: MMC

def mmc(x, y):

return

assert mmc(12, 10) == 60

assert mmc(3, 9) == 9

assert mmc (14, 15) == 210

print('Todos os testes passando!')

Entradas

Saída

x

y

mmc

12

10

60

3

9

9

14

15

210

15 of 26

Exemplo 3: MMC – passando em um só teste

def mmc(x, y):

return 60

assert mmc(12, 10) == 60

assert mmc(3, 9) == 9

assert mmc (14, 15) == 210

print('Todos os testes passando!')

Entradas

Saída

x

y

mmc

12

10

60

3

9

9

14

15

210

16 of 26

Exemplo 3: MMC – passando em todos os testes

def mmc(x, y):

candidato = x

while not (candidato % x == 0 and candidato % y == 0):

candidato += 1

return candidato

assert mmc(12, 10) == 60

assert mmc(3, 9) == 9

assert mmc (14, 15) == 210

print('Todos os testes passando!')

Entradas

Saída

x

y

mmc

12

10

60

3

9

9

14

15

210

17 of 26

Exemplo 3: MMC – otimizando um pouco

def mmc(x, y):

if x > y:

candidato = x

else:

candidato = y

while not (candidato % x == 0 and candidato % y == 0):

candidato += 1

return candidato

assert mmc(12, 10) == 60

assert mmc(3, 9) == 9

assert mmc (14, 15) == 210

print('Todos os testes passando!')

Entradas

Saída

x

y

mmc

12

10

60

3

9

9

14

15

210

18 of 26

Exemplo 3: MMC – simplificando

def mmc(x, y):

candidato = max(x, y)

while not (candidato % x == 0 and candidato % y == 0):

candidato += 1

return candidato

assert mmc(12, 10) == 60

assert mmc(3, 9) == 9

assert mmc (14, 15) == 210

print('Todos os testes passando!')

Entradas

Saída

x

y

mmc

12

10

60

3

9

9

14

15

210

19 of 26

Exemplo 4: quadrado de inteiro

def ao_quadrado(x):

return x + x

assert ao_quadrado(2) == 4

print('Todos os testes passando!')

Entrada

Saída

x

ao_quadrado

2

4

20 of 26

Quantos testes fazer?

def ao_quadrado(x):

return x * x

assert ao_quadrado(2) == 4

assert ao_quadrado(4) == 16

assert ao_quadrado(-9) == 81

assert ao_quadrado(0) == 0

print('Todos os testes passando!')

Entrada

Saída

x

ao_quadrado

2

4

4

16

-9

81

0

0

21 of 26

  • Identificar conjuntos de testes equivalentes entre si
  • Diferenciar os casos especiais
  • Exemplo: classes para verificar se um número é primo
    • Válida: números primos como 2,3, 5 e 7, para os quais a função é verdadeira
    • Válida: números não primos, como 1, 4, 6, 10, 14, para os quais a função é falsa
    • Inválida: valores que não sejam inteiros positivos, como 0, -1, -2, ..., 2.35, 'abc' , etc.

Classes de Equivalência

22 of 26

Exemplo 5: números primos

from funções import é_primo

# testes com números primos

assert é_primo(2)

assert é_primo(3)

assert é_primo(11)

# testes com números não primos

assert not é_primo(1)

assert not é_primo(4)

assert not é_primo(81)

print('Todos os testes passando!')

Entrada

Saída

x

é_primo

2

True

3

True

11

True

1

False

4

False

81

False

23 of 26

Este código passa nos testes?

# arquivo funções.py

def é_primo(numero):

for divisor in range(2, numero//2 + 1):

if numero % divisor == 0:

return False

return True

24 of 26

E este aqui?

# arquivo funções.py

def é_primo(numero):

if numero == 1:

return False

else:

for divisor in range(2, numero//2 + 1):

if numero % divisor == 0:

return False

return True

E as classes inválidas?

25 of 26

  • Vamos deixá-las para uma outra aula sobre testes de software.

Sobre classes inválidas:

26 of 26

Exercícios

  1. Revise a função fatorial feita em aula anterior e escreva um programa que teste esta função usando as técnicas vistas neste capítulo. Se o programa falhar nos testes, corrija-o até que passe em todos os testes.
  2. Use TDD para desenvolver uma função que recebe um valor em reais e retorna o menor número possível de notas de 100, 50, 20, 10, 5 e 1 para produzir este valor. Por exemplo, se a função receber o valor 23, deve retornar 4, porque o menor conjunto de notas que forma 23 contém uma nota de 20 e 3 notas de 1.
  3. Use TDD para desenvolver uma função que recebe dois parâmetros: o primeiro é um número inteiro ou float que indica uma temperatura, o segundo é um caractere ‘F’ ou ‘C’ para indicar Fahrenheit ou Celsius. A função deve retornar a temperatura correspondente convertida para a outra escala. A função deve rejeitar temperaturas abaixo do zero absoluto (-273,15 ºC ou -459,67 ºF). As fórmulas de conversão são:

C = (F – 32) / 1.8

F = 1.8 C + 32