PyNE 2015

TDD com Mock e Orientação a Objetos


Bernardo Fontes


Natal/RN

16 de Maio de 2015

Só para dizer um oi!

twitter.com/bbfontes

github.com/berinhard

garimpo.fm

pessoas.cc

bernardoxhc@gmail.com

berinhard.github.io/talks/


slideshare.net/bernardofontes


youtu.be/-sa0-BJPoxs

Obrigado, Turicas!

Obrigado, Turicas!

# Roteiro - ## Básicos de Orientação a Objetos - ## Test-driven Development (TDD) - ## TDD Com Mocks - ## Dúvidas
## Básicos de Orientação a Objetos - ### *Não é fazer getter e setter*
# Orientação a Objetos? - ## Estratégia de **Design** - ## Definição de **Estado** - ## **Encapsulamento** - ## Colaboração com troca de **Mensagens**
## S.O.L.I.D.
Fluxo de Objetos
## Exemplo Python ```python from 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 teste ```python class Ticket(TestCase): def test_3_returns_fizz(self): self.assertEqual("fizz", fizzbuzz(3)) ```
## Primeira implementação ```python def fizzbuzz(number): return "fizz" class Ticket(TestCase): def test_3_returns_fizz(self): self.assertEqual("fizz", fizzbuzz(3)) ```
## Coding Dojo!!!
## Processo de Design
## Design Emergente - Refatoração - Remoção de Acoplamentos - Duplicidade
## **Exploração** e **Descoberta** - ## cansativo...
## Sem Evidência do Design ```python class 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 no alto nível - ### **Infra** vs **Domínio**
## Referências

Curso TDD - J. B. Rainsberger

## TDD com Mock
## Mock - ### **Simulam** funcionamento de objetos - ### Respeitam **API** dos objetos - ### Viabilizam maneira de fazer **asserções**
## Foco do Domíno nas **Mensagens** - ### Menos **Estado** e mais **Colaboração**
## Implementação de Testes Top-Down
## Need-Driven Development - ### Código **criado** só se **necessário**
## TODO List - ### Recuperar Ingresso - ### Expirá-lo - ### Notificar Usuário
## Entry Point ```python class TestTicketManager(TestCase): def test_expire_ticket(self): manager = TicketManager() manager.expire_ticket(ticket_id=30) ```
## Recuperar Ingresso ```python from 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) ```
```python 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 Ingresso ```python from 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() ```
```python 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" pass ```
## Notificar Usuário ```python from 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) ```
```python 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): def get_by_id(self, id): "Must return a Ticket object" pass class TicketNotificator(object): def notify_expired(self, ticket): pass ```
## Novos testes para garantir **contrato** e **funcionamento unitário** dos componentes
## Respeito ao contrato é **tudo** - ### Comportamentos de **Entrada** - ### Comportamentos de **Saída**
## Referências

Mock Roles, not Objects

GOOS Guided By Tests

pip install mock

## Dúvidas?

Obrigado!


Bernardo Fontes


twitter.com/bbfontes

github.com/berinhard

garimpo.fm

pessoas.cc

bernardoxhc@gmail.com