O que você deve saber sobre Unit Tests.
fisl14 – 03/07/2013
Gustavo Fonseca
gustavo.fons@gmail.com
@gustavonseca
gustavofonseca
Agradecimento
+420.000 artigos científicos
+1.000 periódicos
+9.000.000 citações
www.scielo.org
O que é Unit Test?
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
O framework de unit tests deve...
● Garantir o isolamento dos testes
● Facilitar a configuração do ambiente
● Fomentar a organização dos testes
● Executar os testes
● Produzir relatórios úteis
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
E quando há colaboraçã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 para
andar.')
Composição
1 import unittest
2
3 from cod3 import Carro, Motor
4
5
6 class MotorTests(unittest.TestCase):
7 def setUp(self):
8 self.motor = Motor()
9
10 def test_estado_padrao_eh_desligado(self):
11 self.assertFalse(self.motor.ligado)
12
13 def test_ligar(self):
14 self.motor.ligar()
15 self.assertTrue(self.motor.ligado)
16
17 def test_desligar(self):
18 self.motor.ligar()
19
20 self.assertTrue(self.motor.ligado)
21 self.motor.desligar()
22 self.assertFalse(self.motor.ligado)
23
24
25 class CarroTests(unittest.TestCase):
26 def setUp(self):
27 self.carro = Carro()
28
29 def test_dar_partida(self):
30 self.carro.dar_partida()
31 self.assertTrue(self.carro.esta_ligado())
32
33 def test_andar(self):
34 self.carro.dar_partida()
35 self.assertIsNone(self.carro.andar())
36
37 def test_andar_com_carro_desligado_levanta_excecao(self):
38 self.assertRaises(RuntimeError, self.carro.andar)
39
Uma instância de
Motor foi criada
Motor().ligar()
Isolamento de dependências
dublê
Dublês de teste
● stub
● dummy
● fake
http://martinfowler.com/articles/mocksArentStubs.html
● mock
Cidadãos de primeira 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 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
para andar.')
Composição via
argumento na
construção do
objeto
Stub
1 import unittest
2
3 from cod3 import Carro, Motor
4
5
6 class MotorTests(unittest.TestCase):
7 """Suprimidos os testes para economizar tela"""
8
9 class CarroTests(unittest.TestCase):
10 def setUp(self):
11
12 class MotorStub(object):
13 def __init__(self):
14 self.ligado = False
15 def ligar(self): return None
16 def desligar(self): return None
17
18 self.carro = Carro(motor=MotorStub)
19
20 def test_dar_partida(self):
21 self.carro.motor.ligado = True
22
23 self.carro.dar_partida()
24 self.assertTrue(self.carro.esta_ligado())
25
26 def test_andar(self):
27 self.carro.motor.ligado = True
28
29 self.carro.dar_partida()
30 self.assertIsNone(self.carro.andar())
31
32 def test_andar_com_carro_desligado_levanta_excecao(self):
33 self.assertRaises(RuntimeError, self.carro.andar)
34
Implementa a interface
do objeto, com retornos
previsíveis.
O dublê entra em ação!
Mock
1 import mocker
2
3 from cod3 import Carro, Motor
4
5
6 class MotorTests(mocker.MockerTestCase):
7 """Suprimidos os testes para economizar tela"""
8
9 class CarroTests(mocker.MockerTestCase):
10
11 def test_dar_partida(self):
12 # Inicio do treinamento
13 MotorMock = self.mocker.mock()
14
15 MotorMock()
16 self.mocker.result(MotorMock)
17
18 MotorMock.ligar()
19 self.mocker.result(None)
20
21 MotorMock.ligado
22 self.mocker.result(True)
23
24 self.mocker.replay()
25 # Fim do treinamento
26
27 carro = Carro(motor=MotorMock)
28 carro.dar_partida()
29 self.assertTrue(carro.esta_ligado())
30
31 def test_andar(self):
32 """Suprimido para economizar tela"""
33
34 def
test_andar_com_carro_desligado_levanta_excecao(self):
35 """Suprimido para economizar tela"""
http://docs.python.org/3.3/library/unittest.mock.html
labix.org/mocker
Treinando o mock
Fim do treinamento
1 import mocker
2
3 from cod3 import Carro, Motor
4
5
6 class MotorTests(mocker.MockerTestCase):
7 """Suprimidos os testes para economizar tela"""
8
9 class CarroTests(mocker.MockerTestCase):
10
11 def test_dar_partida(self):
12 # Inicio do treinamento
13 MotorMock = self.mocker.mock()
14
15 MotorMock()
16 self.mocker.result(MotorMock)
17
18 MotorMock.ligar()
19 self.mocker.result(None)
20
21 self.mocker.replay()
22 # Fim do treinamento
23
24 carro = Carro(motor=MotorMock)
25 carro.dar_partida()
26 self.assertTrue(carro.esta_ligado())
27
28 def test_andar(self):
29 """Suprimido para economizar tela"""
30
31 def
test_andar_com_carro_desligado_levanta_excecao(self):
32 """Suprimido para economizar tela"""
Removido o treino do
atributo .ligado
Unexpected expression
Estratégias
● Cobertura de linhas de código
● Cobertura de caminhos
● Classes de equivalência
● Fronteiras
● Erros
Outras siglas e nomes conhecidos
● IoC (Inversion of control)
● DI (Dependency injection)
● Fixtures
● Doctests (Python)
Obrigado!
Dúvidas?
Gustavo Fonseca
gustavo.fons@gmail.com
@gustavonseca
gustavofonseca

O que você deve saber sobre Unit Tests.

  • 1.
    O que vocêdeve saber sobre Unit Tests. fisl14 – 03/07/2013 Gustavo Fonseca gustavo.fons@gmail.com @gustavonseca gustavofonseca
  • 2.
    Agradecimento +420.000 artigos científicos +1.000periódicos +9.000.000 citações www.scielo.org
  • 3.
    O que éUnit Test? 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
  • 4.
    O framework deunit tests deve... ● Garantir o isolamento dos testes ● Facilitar a configuração do ambiente ● Fomentar a organização dos testes ● Executar os testes ● Produzir relatórios úteis
  • 5.
    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
  • 6.
    E quando hácolaboraçã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 para andar.') Composição
  • 7.
    1 import unittest 2 3from cod3 import Carro, Motor 4 5 6 class MotorTests(unittest.TestCase): 7 def setUp(self): 8 self.motor = Motor() 9 10 def test_estado_padrao_eh_desligado(self): 11 self.assertFalse(self.motor.ligado) 12 13 def test_ligar(self): 14 self.motor.ligar() 15 self.assertTrue(self.motor.ligado) 16 17 def test_desligar(self): 18 self.motor.ligar() 19 20 self.assertTrue(self.motor.ligado) 21 self.motor.desligar() 22 self.assertFalse(self.motor.ligado) 23 24 25 class CarroTests(unittest.TestCase): 26 def setUp(self): 27 self.carro = Carro() 28 29 def test_dar_partida(self): 30 self.carro.dar_partida() 31 self.assertTrue(self.carro.esta_ligado()) 32 33 def test_andar(self): 34 self.carro.dar_partida() 35 self.assertIsNone(self.carro.andar()) 36 37 def test_andar_com_carro_desligado_levanta_excecao(self): 38 self.assertRaises(RuntimeError, self.carro.andar) 39 Uma instância de Motor foi criada Motor().ligar()
  • 8.
  • 9.
    Dublês de teste ●stub ● dummy ● fake http://martinfowler.com/articles/mocksArentStubs.html ● mock
  • 10.
    Cidadãos de primeiraclasse 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 para andar.') Composição via argumento na construção do objeto
  • 11.
    Stub 1 import unittest 2 3from cod3 import Carro, Motor 4 5 6 class MotorTests(unittest.TestCase): 7 """Suprimidos os testes para economizar tela""" 8 9 class CarroTests(unittest.TestCase): 10 def setUp(self): 11 12 class MotorStub(object): 13 def __init__(self): 14 self.ligado = False 15 def ligar(self): return None 16 def desligar(self): return None 17 18 self.carro = Carro(motor=MotorStub) 19 20 def test_dar_partida(self): 21 self.carro.motor.ligado = True 22 23 self.carro.dar_partida() 24 self.assertTrue(self.carro.esta_ligado()) 25 26 def test_andar(self): 27 self.carro.motor.ligado = True 28 29 self.carro.dar_partida() 30 self.assertIsNone(self.carro.andar()) 31 32 def test_andar_com_carro_desligado_levanta_excecao(self): 33 self.assertRaises(RuntimeError, self.carro.andar) 34 Implementa a interface do objeto, com retornos previsíveis. O dublê entra em ação!
  • 12.
    Mock 1 import mocker 2 3from cod3 import Carro, Motor 4 5 6 class MotorTests(mocker.MockerTestCase): 7 """Suprimidos os testes para economizar tela""" 8 9 class CarroTests(mocker.MockerTestCase): 10 11 def test_dar_partida(self): 12 # Inicio do treinamento 13 MotorMock = self.mocker.mock() 14 15 MotorMock() 16 self.mocker.result(MotorMock) 17 18 MotorMock.ligar() 19 self.mocker.result(None) 20 21 MotorMock.ligado 22 self.mocker.result(True) 23 24 self.mocker.replay() 25 # Fim do treinamento 26 27 carro = Carro(motor=MotorMock) 28 carro.dar_partida() 29 self.assertTrue(carro.esta_ligado()) 30 31 def test_andar(self): 32 """Suprimido para economizar tela""" 33 34 def test_andar_com_carro_desligado_levanta_excecao(self): 35 """Suprimido para economizar tela""" http://docs.python.org/3.3/library/unittest.mock.html labix.org/mocker Treinando o mock Fim do treinamento
  • 13.
    1 import mocker 2 3from cod3 import Carro, Motor 4 5 6 class MotorTests(mocker.MockerTestCase): 7 """Suprimidos os testes para economizar tela""" 8 9 class CarroTests(mocker.MockerTestCase): 10 11 def test_dar_partida(self): 12 # Inicio do treinamento 13 MotorMock = self.mocker.mock() 14 15 MotorMock() 16 self.mocker.result(MotorMock) 17 18 MotorMock.ligar() 19 self.mocker.result(None) 20 21 self.mocker.replay() 22 # Fim do treinamento 23 24 carro = Carro(motor=MotorMock) 25 carro.dar_partida() 26 self.assertTrue(carro.esta_ligado()) 27 28 def test_andar(self): 29 """Suprimido para economizar tela""" 30 31 def test_andar_com_carro_desligado_levanta_excecao(self): 32 """Suprimido para economizar tela""" Removido o treino do atributo .ligado Unexpected expression
  • 14.
    Estratégias ● Cobertura delinhas de código ● Cobertura de caminhos ● Classes de equivalência ● Fronteiras ● Erros
  • 15.
    Outras siglas enomes conhecidos ● IoC (Inversion of control) ● DI (Dependency injection) ● Fixtures ● Doctests (Python)
  • 16.

Notas do Editor

  • #4 Unit testing é um método onde unidades de código fonte (funções, procedures, classes, módulos) são testadas para garantir seu funcionamento conforme o esperado. Para cada unidade de código fonte, são verificados N casos de teste. Sendo cada um chamado de Unit Test. A melhor tradução para pt-br é Teste de Unidade, e não Teste Unitário. Nem todas as unidades são tão simples de serem testadas. Algumas necessitam um estado global específico para que os casos de teste possam ser reproduzidos. Outras alteram o estado de objetos ou o estado global.
  • #10 A analogia das caixas é relativa à camada da aplicação que é objeto de teste. Do ponto de vista de um testador humano, virtualmente todos os testes de unidade são de caixa branca.