tdd com mock e orientação a objetos (pyne 2015)
TRANSCRIPT
PyNE 2015TDD com Mock e Orientação a Objetos
Bernardo FontesNatal/RN
16 de Maio de 2015
Só para dizer um oi!twitter.com/bbfontesgithub.com/berinhard
garimpo.fmpessoas.cc
github.com/berinhard/talks
Obrigado, Turicas!
Obrigado, Turicas!
RoteiroBásicos de Orientação aObjetosTest-driven Development(TDD)TDD Com MocksDúvidas
Básicos de Orientação aObjetos
Não é fazer getter e setter
Orientação aObjetos?
Estratégia de DesignDefinição de EstadoEncapsulamentoColaboração com troca deMensagens
S.O.L.I.D.
Exemplo Pythonfrom datetime import date
class Ticket(object):
def __init__(self, buyer, price, schedule_date): self.buyer = buyer self.price = price self.schedule_date = schedule_date
def has_expired(self): return date.today() > self.schedule_date
#############################
ticket = Ticket("Bernardo", 10, date(2015, 10, 10))if not ticket.has_expired(): #processa ticket válido
Referências
Object Mentor
Test-driven Development (TDD)
Primeiro o testeclass Ticket(TestCase):
def test_3_returns_fizz(self): self.assertEqual("fizz", fizz(3))
Primeira implementaçãodef foo(number): return "fizz"
class Ticket(TestCase):
def test_3_returns_fizz(self): self.assertEqual("fizz", fizz(3))
Coding Dojo!!!
Processo de Design
Design EmergenteRefatoraçãoRemoção de AcoplamentosDuplicidade
Exploração e Descobertacansativo...
Sem Evidência do Designclass TestTicketManager(TestCase):
def test_expire_ticket(self): ticket = Ticket.objects.create(id=30) self.assertFalse(ticket.expired)
manager = TicketManager() manager.expire_ticket(ticket_id=30)
ticket = Ticket.objects.get(id=30) self.assertTrue(ticket.expired)
Difícil de começar a testar noalto nível
Infra vs Domínio
Referências
Curso TDD - J. B. Rainsberger
TDD com Mock
MockSimulam funcionamento de objetosRespeitam API dos objetosViabilizam maneira de fazer asserções
Foco do Domíno nasMensagens
Menos Estado e mais Colaboração
Implementação de Testes Top-Down
Need-Driven DevelopmentCódigo criado só se necessário
TODO ListRecuperar IngressoExpirá-loNotificar Usuário
Entry Pointclass TestTicketManager(TestCase):
def test_expire_ticket(self): manager = TicketManager() manager.expire_ticket(ticket_id=30)
Recuperar Ingressofrom mock import Mock
class TestTicketManager(TestCase):
def test_expire_ticket(self): tickets_repository = Mock(TicketsRepository) tickets_repository.get_by_id.return_value = Ticket()
manager = TicketManager(tickets_repository) manager.expire_ticket(ticket_id=30)
tickets_repository.get_by_id.assert_called_once_with(30)
class TicketManager(object):
def __init__(self, tickets_repository): self.repository = tickets_repository
def expire_ticket(self, ticket_id): self.repository.get_by_id(ticket_id)
class Ticket(object): pass
class TicketsRepository(object):
def get_by_id(self, id): "Must return a Ticket object" pass
Expirar Ingressofrom mock import Mock
class TestTicketManager(TestCase):
def test_expire_ticket(self): ticket = Mock(Ticket) tickets_repository = Mock(TicketsRepository) tickets_repository.get_by_id.return_value = ticket
manager = TicketManager(tickets_repository) manager.expire_ticket(ticket_id=30)
tickets_repository.get_by_id.assert_called_once_with(30) ticket.expire.assert_called_once_with()
class TicketManager(object):
def __init__(self, tickets_repository): self.repository = tickets_repository
def expire_ticket(self, ticket_id): ticket = self.repository.get_by_id(ticket_id) ticket.expire()
class Ticket(object):
def expire(self): pass
class TicketsRepository(object):
def get_by_id(self, id): "Must return a Ticket object"
Notificar Usuáriofrom mock import Mock
class TestTicketManager(TestCase):
def test_expire_ticket(self): ticket = Mock(Ticket) tickets_repository = Mock(TicketsRepository) tickets_repository.get_by_id.return_value = ticket notificator = Mock(TicketNotificator)
manager = TicketManager(tickets_repository, notificator) manager.expire_ticket(ticket_id=30)
tickets_repository.get_by_id.assert_called_once_with(30) ticket.expire.assert_called_once_with() notificator.notify_expired.assert_called_once_with(ticket)
class TicketManager(object):
def __init__(self, tickets_repository, notificator): self.repository = tickets_repository self.notificator = notificator
def expire_ticket(self, ticket_id): ticket = self.repository.get_by_id(ticket_id) ticket.expire() self.notificator.notify_expired(ticket)
class Ticket(object):
def expire(self): pass
class TicketsRepository(object):
Respeito ao contrato é tudoComportamentos de EntradaComportamentos de Saída
Novos testes para garantircontrato e funcionamentounitário dos componentes
Referências
Mock Roles, not Objects
GOOS Guided By Tests
pip install mock
Dúvidas?
Obrigado!Bernardo Fontes
twitter.com/bbfontesgithub.com/berinhard
garimpo.fmpessoas.cc