Ensaio sobre testes automatizados

TDC2014 – 09/08/2014
Gustavo Fonseca
@gustavonseca

gustavofonseca
1
Níveis de teste
● Testes de aceitação
● Testes de integração
● Testes de sistema
● ...
● Testes de unidade
2
3
Testes de Unidade

4
O que é Teste de Unidade?
1 #coding: utf-8	
2 	
3 def saudar(nome):	
4 return u'Olá, %s.' % nome	
5 	
6 	
7 # garantir que o nome do fulano passado como	
8 # argumento seja utilizado na saudação	
9 assert saudar('Gustavo') == u'Olá, Gustavo.'	
10 	
11 # garantir que seja retornado um objeto unicode	
12 assert isinstance(saudar('foo'), unicode)	
Unidade objeto dos testes
Casos de teste
5
Características
● Garantir o isolamento dos testes
● Facilitar a configuração do ambiente
● Fomentar a organização dos testes
● Executar os testes
● Produzir relatórios úteis
6
1 #coding: utf-8	
2 import unittest	
3 	
4 	
5 def saudar(nome):	
6 return u'Olá, %s.' % nome	
7 	
8 	
9 class SaudarTests(unittest.TestCase):	
10 	
11 def test_nome_do_fulano_seja_utilizado_na_saudacao(self):	
12 self.assertEqual(saudar('Gustavo'), u'Olá, Gustavo.')	
13 	
14 def test_objeto_retornado_tipo_unicode(self):	
15 self.assertIsInstance(saudar('foo'), unicode)	
Resumo da execução
dos testes
Casos de teste são
agrupados em
subclasses de
unittest.TestCase
O ambiente pode ser
preparado por meio
dos métodos setUp e
tearDown
unittest (stdlib)
http://docs.python.org/2.7/library/unittest.html
7
Associação
8
Exemplo de Composição
1 class Motor(object):	
2 def __init__(self):	
3 self.ligado = False	
4 	
5 def ligar(self):	
6 self.ligado = True	
7 	
8 def desligar(self):	
9 self.ligado = False	
10 	
11 	
12 class Carro(object):	
13 def __init__(self):	
14 self.motor = Motor()	
15 	
16 def dar_partida(self):	
17 self.motor.ligar()	
18 	
19 def esta_ligado(self):	
20 return self.motor.ligado	
21 	
22 def andar(self):	
23 if self.esta_ligado():	
24 print 'Andando... uhul!'	
25 else:	
26 raise RuntimeError('O carro precisa estar ligado.')	
Composição
9
1 import unittest	
2 	
3 from cod3 import Carro, Motor	
4 	
5 	
6 class MotorTests(unittest.TestCase):	
7 """	
8 Os testes foram suprimidos para	
9 economizar espaco	
10 """	
11 	
12 class CarroTests(unittest.TestCase):	
13 def setUp(self):	
14 self.carro = Carro()	
15 	
16 def test_dar_partida(self):	
17 self.carro.dar_partida()	
18 self.assertTrue(self.carro.esta_ligado())	
19 	
20 def test_andar(self):	
21 self.carro.dar_partida()	
22 self.assertIsNone(self.carro.andar())	
23 	
24 def test_andar_com_carro_desligado_levanta_excecao(self):	
25 self.assertRaises(RuntimeError, self.carro.andar)	
26 	
Uma instância de
Motor foi criada
Motor().ligar()
10
Isolamento de dependências
dublê
11
__init__
1 class Motor(object):	
2 def __init__(self):	
3 self.ligado = False	
4 	
5 def ligar(self):	
6 self.ligado = True	
7 	
8 def desligar(self):	
9 self.ligado = False	
10 	
11 	
12 class Carro(object):	
13 def __init__(self, motor=Motor):	
14 self.motor = motor()	
15 	
16 def dar_partida(self):	
17 self.motor.ligar()	
18 	
19 def esta_ligado(self):	
20 return self.motor.ligado	
21 	
22 def andar(self):	
23 if self.esta_ligado():	
24 print 'Andando... uhul!'	
25 else:	
26 raise RuntimeError('O carro precisa estar ligado.')	
Composição via
argumento na
inicialização do
objeto
12
Atributo de classe
1 class Motor(object):	
2 def __init__(self):	
3 self.ligado = False	
4 	
5 def ligar(self):	
6 self.ligado = True	
7 	
8 def desligar(self):	
9 self.ligado = False	
10 	
11 	
12 class Carro(object):	
13 classe_motor = Motor	
14 	
15 def __init__(self):	
16 self.motor = self.classe_motor()	
17 	
18 def dar_partida(self):	
19 self.motor.ligar()	
20 	
21 def esta_ligado(self):	
22 return self.motor.ligado	
23 	
24 def andar(self):	
25 if self.esta_ligado():	
26 print 'Andando... uhul!'	
27 else:	
28 raise RuntimeError('O carro precisa estar ligado.')	 13
Composição via atributo
de classe
Atributo de classe (cont.)
14
from unittest import mock # python3	
!
with mock.patch.object(Carro, 'classe_motor', autospec=True) as motor_teste:	
motor_teste.return_value = MotorDuble	
!
carro = Carro()	
# testes aqui...
Dublês de teste
dummy - fake - stub - mock
http://martinfowler.com/articles/mocksArentStubs.html 15
Stub
class CarroTests(unittest.TestCase):	
def setUp(self):	
!
class MotorStub(object):	
def __init__(self):	
self.ligado = False	
def ligar(self): return None	
def desligar(self): return None	
!
self.carro = Carro(motor=MotorStub)	
!
def test_dar_partida(self):	
self.carro.motor.ligado = True	
!
self.carro.dar_partida()	
self.assertTrue(self.carro.esta_ligado())	
!
def test_andar(self):	
self.carro.motor.ligado = True	
!
self.carro.dar_partida()	
self.assertIsNone(self.carro.andar())	
!
def test_andar_com_carro_desligado_levanta_excecao(self):	
self.assertRaises(RuntimeError, self.carro.andar)	
!
Implementa a
interface do objeto,
com retornos
previsíveis.
O dublê entra em ação! rá!
16
Configuração de estado
pré-teste.
Mock
import mocker # python 2 apenas =/	
!
from cod3 import Carro	
!
!
class CarroTests(mocker.MockerTestCase):	
!
def test_dar_partida(self):	
# Inicio do treinamento	
MotorMock = self.mocker.mock()	
!
MotorMock()	
self.mocker.result(MotorMock)	
!
MotorMock.ligar()	
self.mocker.result(None)	
!
MotorMock.ligado	
self.mocker.result(True)	
!
self.mocker.replay()	
# Fim do treinamento	
!
carro = Carro(motor=MotorMock)	
carro.dar_partida()	
self.assertTrue(carro.esta_ligado())	
Ver também: http://docs.python.org/3.3/library/unittest.mock.html
labix.org/mocker
17
import mocker	
!
from cod3 import Carro	
!
!
class CarroTests(mocker.MockerTestCase):	
!
def test_dar_partida(self):	
# Inicio do treinamento	
MotorMock = self.mocker.mock()	
!
MotorMock()	
self.mocker.result(MotorMock)	
!
MotorMock.ligar()	
self.mocker.result(None)	
!
#MotorMock.ligado	
#self.mocker.result(True)	
!
self.mocker.replay()	
# Fim do treinamento	
!
carro = Carro(motor=MotorMock)	
carro.dar_partida()	
self.assertTrue(carro.esta_ligado())	
Removido o treino do
atributo .ligado
18
19
"Mocke" com moderação
• Testes menos manuteníveis
• Mudanças de interface (API)
• Inconsistências entre "treinamentos"
• Prefira "mockar" os pontos de integração
• Teste os mocks! o.O
Pontos de integração
20
21
Cliente REST
http://git.io/S9YCrg
Grato!

Dúvidas?
Gustavo Fonseca
@gustavonseca

gustavofonseca
22

Ensaio sobre testes automatizados

  • 1.
    Ensaio sobre testesautomatizados
 TDC2014 – 09/08/2014 Gustavo Fonseca @gustavonseca
 gustavofonseca 1
  • 2.
    Níveis de teste ●Testes de aceitação ● Testes de integração ● Testes de sistema ● ... ● Testes de unidade 2
  • 3.
  • 4.
  • 5.
    O que éTeste de Unidade? 1 #coding: utf-8 2 3 def saudar(nome): 4 return u'Olá, %s.' % nome 5 6 7 # garantir que o nome do fulano passado como 8 # argumento seja utilizado na saudação 9 assert saudar('Gustavo') == u'Olá, Gustavo.' 10 11 # garantir que seja retornado um objeto unicode 12 assert isinstance(saudar('foo'), unicode) Unidade objeto dos testes Casos de teste 5
  • 6.
    Características ● Garantir oisolamento dos testes ● Facilitar a configuração do ambiente ● Fomentar a organização dos testes ● Executar os testes ● Produzir relatórios úteis 6
  • 7.
    1 #coding: utf-8 2import unittest 3 4 5 def saudar(nome): 6 return u'Olá, %s.' % nome 7 8 9 class SaudarTests(unittest.TestCase): 10 11 def test_nome_do_fulano_seja_utilizado_na_saudacao(self): 12 self.assertEqual(saudar('Gustavo'), u'Olá, Gustavo.') 13 14 def test_objeto_retornado_tipo_unicode(self): 15 self.assertIsInstance(saudar('foo'), unicode) Resumo da execução dos testes Casos de teste são agrupados em subclasses de unittest.TestCase O ambiente pode ser preparado por meio dos métodos setUp e tearDown unittest (stdlib) http://docs.python.org/2.7/library/unittest.html 7
  • 8.
  • 9.
    Exemplo de Composição 1class Motor(object): 2 def __init__(self): 3 self.ligado = False 4 5 def ligar(self): 6 self.ligado = True 7 8 def desligar(self): 9 self.ligado = False 10 11 12 class Carro(object): 13 def __init__(self): 14 self.motor = Motor() 15 16 def dar_partida(self): 17 self.motor.ligar() 18 19 def esta_ligado(self): 20 return self.motor.ligado 21 22 def andar(self): 23 if self.esta_ligado(): 24 print 'Andando... uhul!' 25 else: 26 raise RuntimeError('O carro precisa estar ligado.') Composição 9
  • 10.
    1 import unittest 2 3 from cod3 import Carro, Motor 4 5 6 class MotorTests(unittest.TestCase): 7 """ 8 Os testes foram suprimidos para 9 economizar espaco 10 """ 11 12 class CarroTests(unittest.TestCase): 13 def setUp(self): 14 self.carro = Carro() 15 16 def test_dar_partida(self): 17 self.carro.dar_partida() 18 self.assertTrue(self.carro.esta_ligado()) 19 20 def test_andar(self): 21 self.carro.dar_partida() 22 self.assertIsNone(self.carro.andar()) 23 24 def test_andar_com_carro_desligado_levanta_excecao(self): 25 self.assertRaises(RuntimeError, self.carro.andar) 26 Uma instância de Motor foi criada Motor().ligar() 10
  • 11.
  • 12.
    __init__ 1 class Motor(object): 2def __init__(self): 3 self.ligado = False 4 5 def ligar(self): 6 self.ligado = True 7 8 def desligar(self): 9 self.ligado = False 10 11 12 class Carro(object): 13 def __init__(self, motor=Motor): 14 self.motor = motor() 15 16 def dar_partida(self): 17 self.motor.ligar() 18 19 def esta_ligado(self): 20 return self.motor.ligado 21 22 def andar(self): 23 if self.esta_ligado(): 24 print 'Andando... uhul!' 25 else: 26 raise RuntimeError('O carro precisa estar ligado.') Composição via argumento na inicialização do objeto 12
  • 13.
    Atributo de classe 1class Motor(object): 2 def __init__(self): 3 self.ligado = False 4 5 def ligar(self): 6 self.ligado = True 7 8 def desligar(self): 9 self.ligado = False 10 11 12 class Carro(object): 13 classe_motor = Motor 14 15 def __init__(self): 16 self.motor = self.classe_motor() 17 18 def dar_partida(self): 19 self.motor.ligar() 20 21 def esta_ligado(self): 22 return self.motor.ligado 23 24 def andar(self): 25 if self.esta_ligado(): 26 print 'Andando... uhul!' 27 else: 28 raise RuntimeError('O carro precisa estar ligado.') 13 Composição via atributo de classe
  • 14.
    Atributo de classe(cont.) 14 from unittest import mock # python3 ! with mock.patch.object(Carro, 'classe_motor', autospec=True) as motor_teste: motor_teste.return_value = MotorDuble ! carro = Carro() # testes aqui...
  • 15.
    Dublês de teste dummy- fake - stub - mock http://martinfowler.com/articles/mocksArentStubs.html 15
  • 16.
    Stub class CarroTests(unittest.TestCase): def setUp(self): ! classMotorStub(object): def __init__(self): self.ligado = False def ligar(self): return None def desligar(self): return None ! self.carro = Carro(motor=MotorStub) ! def test_dar_partida(self): self.carro.motor.ligado = True ! self.carro.dar_partida() self.assertTrue(self.carro.esta_ligado()) ! def test_andar(self): self.carro.motor.ligado = True ! self.carro.dar_partida() self.assertIsNone(self.carro.andar()) ! def test_andar_com_carro_desligado_levanta_excecao(self): self.assertRaises(RuntimeError, self.carro.andar) ! Implementa a interface do objeto, com retornos previsíveis. O dublê entra em ação! rá! 16 Configuração de estado pré-teste.
  • 17.
    Mock import mocker #python 2 apenas =/ ! from cod3 import Carro ! ! class CarroTests(mocker.MockerTestCase): ! def test_dar_partida(self): # Inicio do treinamento MotorMock = self.mocker.mock() ! MotorMock() self.mocker.result(MotorMock) ! MotorMock.ligar() self.mocker.result(None) ! MotorMock.ligado self.mocker.result(True) ! self.mocker.replay() # Fim do treinamento ! carro = Carro(motor=MotorMock) carro.dar_partida() self.assertTrue(carro.esta_ligado()) Ver também: http://docs.python.org/3.3/library/unittest.mock.html labix.org/mocker 17
  • 18.
    import mocker ! from cod3import Carro ! ! class CarroTests(mocker.MockerTestCase): ! def test_dar_partida(self): # Inicio do treinamento MotorMock = self.mocker.mock() ! MotorMock() self.mocker.result(MotorMock) ! MotorMock.ligar() self.mocker.result(None) ! #MotorMock.ligado #self.mocker.result(True) ! self.mocker.replay() # Fim do treinamento ! carro = Carro(motor=MotorMock) carro.dar_partida() self.assertTrue(carro.esta_ligado()) Removido o treino do atributo .ligado 18
  • 19.
    19 "Mocke" com moderação •Testes menos manuteníveis • Mudanças de interface (API) • Inconsistências entre "treinamentos" • Prefira "mockar" os pontos de integração • Teste os mocks! o.O
  • 20.
  • 21.
  • 22.