TDD
Test Driven Development
{
“Nome” : “Guilherme Botossi”,
“Profissão” : “Software Engineer”,
“Empresa” : “Creditas”
“Mercados” : [
“Fiscal”,
“Varejista”,
“Financeiro”,
“Educacional”,
“Pesquisa Cientifica”
],
“Redes_Sociais” : {
“Github”: “@guilhermebotossi”,
“Linkedin” : “@guilhermebotossi”,
“Instagram” : “@guilhermebotossi”
}
}
O que é TDD?
● Test Driven Development.
● Metodologia de desenvolvimento baseado em testes.
● Os testes unitários são escritos antes da funcionalidade.
Tipos de testes e distribuição:
CustoeComplexidade
O que é Teste Unitario?
Um teste unitário(de uma unidade) é o teste da menor parte
testável de um programa.
A unidade pode ser uma instrução, método, classe,
funcionalidade e etc.
Depende muito do que é a menor parte que seu software
pode ser testado.
Cada teste deve ser responsável por testar apenas um
comportamento
O Teste unitário deve ser (F.I.R.S.T.)
● Fast ⇒ Rápido;
● Independent ⇒ Independente;
● Repeatable ⇒ Repetitivo;
● Self-Verifiable ⇒ Auto-Verificável;
● Timily ⇒ Escrito no momento certo;
O que é Teste de Integração?
É o teste utilizando os recursos reais sem assistência de
test doubles, ou seja ele garante que tudo funciona
conforme testado.
Se eu tenho testes unitários, por que eu preciso de
testes de Integração?
Como Funciona
As 3 Leis do TDD
O desenvolvimento deve ser orientado por essas 3 leis:
1. You are not allowed to write any production code unless it is to make a failing unit test pass.
2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures
are failures.
3. You are not allowed to write any more production code than is sufficient to pass the one failing unit
test.
Essas 3 leis em resumo fazem alusão ao uso de “Baby Steps”.
Robert C. Martin
aka Uncle Bob
Ciclo de Desenvolvimento de Testes Unitários
1 - RED - Erro nos teste;
2 - GREEN - Corrigir o erro no teste ou
corrigir o teste, da maneira mais fácil
possível ;
3 - REFACTOR - Limpar a casa, uma vez
que seu teste passou, agora você pode
pensar na melhor maneira de fazer;
Formato do Teste
Temos os 3 A’s :
● Arrange - É a preparação, seja de ambiente, variáveis, banco de dados, test
doubles e etc. Tudo aquilo que o teste irá utilizar.
● Act - Realizamos a chamada do SUT(System Under Test)
● Assert - É o momento de verificarmos se o teste trouxe os resultados
esperados.
Vantagens
● Evita future proofing(?)
● Garante consistência
● Evita desperdícios
● Refatoração em ambiente seguro
● Os testes são uma documentação
● Reduz esforços de retrabalho
Custo de correção de falhas
Desvantagens
● Tempo de desenvolvimento*
● Testes devem ser mantidos
● Deve ser um esforço de time
● Difícil ser aplicado em código legados
● No início tem custo alto no desenvolvimento
● Refatorações, requerem também a refatoração dos testes
O que ele não garante?
● Código livre de bugs
● Qualidade
● Ausência de Erros
Test Doubles
Dummy
● São Placeholders, geralmente eles são usados apenas para preencher listas
de parâmetros.
● Poderia ser substituido por Null
● São objetos que não interagem diretamente com o SUT
● O conteúdo não é relevante, mas o objeto é obrigatório
@Test
public void addCustomerTest() {
//método privado no teste pra criar um customer qualquer
//Customer customer = createDummyCustomer();
//Ou
Customer dummy = mock(Customer.class);
AddressBook addressBook = new AddressBook();
addressBook.addCustomer(customer);
assertEquals(1, addressBook.getNumberOfCustomers());
}
Stub
● Fornecem respostas pré configuradas às chamadas feitas durante o teste.
● Podemos usar para testar o caminho feliz e os casos com exceção
public class AcceptingAuthorizerStub implements Authorizer {
public Boolean authorize(String username, String password) {
return true;
}
}
EntityManager entityManager = mock(EntityManager.class);
when(entityManager.find(Customer.class,1L)).thenReturn(sampleCustomer);
Spy
● Spies são Stubs que registram informações de suas iterações.
● Podendo ou não ser a chamada do método real
@Test
public void whenStubASpy_thenStubbed() {
List<String> list = new ArrayList<String>();
List<String> spyList = Mockito.spy(list);
assertEquals(0, spyList.size());
Mockito.doReturn(100).when(spyList).size();
assertEquals(100, spyList.size());
}
@Test
public void whenSpyingOnList_thenCorrect() {
List<String> list = new ArrayList<String>();
List<String> spyList = Mockito.spy(list);
spyList.add("one");
spyList.add("two");
Mockito.verify(spyList).add("one");
Mockito.verify(spyList).add("two");
assertEquals(2, spyList.size());
}
Mock
● Mocks são objetos configurados, onde define-se o comportamento das
chamadas esperadas durante o teste.
● Podem lançar uma exceção se receberem uma chamada que não
configurada
● Permite verificação dos comportamentos configurados
UUIDProvider uuidProvider = mock(UUIDProvider.class)
when(uuidProvider.isValid(uuid)).thenReturn(true);
UUID id = UUID.fromString(uuid);
when(uuidProvider.fromString(str)).thenReturn(id);
verify(uuidProvider).isValid(str);
verify(uuidProvider).fromString(str);
Fake
● É uma implementação real, voltada para os testes e que não será usada em
produção
● Tem um comportamento voltado regras de negócio
● Podem ser extremamente complexos
● Normalmente representam um serviço externo, tal qual um banco de dado,
ou um sistema de autenticação.
public class AcceptingAuthorizerFake implements Authorizer {
public Boolean authorize(String username, String password) {
return username.equals("Bob");
}
}
Test Doubles
Escolas de TDD
Classicist (Detroit)
● Bottom-up / Middle-out
● Teste da API pública
● Avanço através de pequenos incrementos
● Liberdade para refatorações agressivas na
implementação
● Chances de criar um YAGNI
● Testes Superficiais, foco no resultado
● Teste de Regressão em uma única suíte
● Testa estado
Mockist (London)
● Top-down
● Teste de todas as camadas
● Alto acoplamento entre testes e
implementação
● Reescrever ao invés de re-fatorar
● Design Limpo e minimalista
● Grande quantidade de test doubles
● Teste regressão depende de mais de uma
suíte
● Testa Comportamento
System Under Test(SUT)
public BoletoVO listById(String id) {
if(uuidProvider.isValid(id)) {
UUID uuid = uuidProvider.fromString(id);
Optional<Boleto> bo =
boletoRepository.findById(uuid);
if(bo.isPresent()) {
return boletoMapper.mapToVO(bo.get());
} else {
throw new BankslipRecordNotFoundException();
}
}
throw new InvalidUUIDFormatException();
}
@Test
public void listById_called_returnOK() {
String uuid = "8c9f029f-53d2-4f75-8cf5-
75a13c4046e3";
BoletoVO bvo =
boletoService.listById(uuid);
assertNotNull(bvo);
assertEquals(uuid, bvo.getId().toString());
@Autowired
private BoletoService boletoService;
@Autowired
@Qualifier(“fakeBoletoRepository”)
private BoletoRepository
boletoRepository;
Exemplo-Classicist
Exemplo-Mockist @Test
public void listById_called_returnOK() {
String uuid = "8c9f029f-53d2-4f75-8cf5-
75a13c4046e3";
when(uuidProvider.isValid(uuid)).thenReturn(true);
UUID id = UUID.fromString(uuid);
when(uuidProvider.fromString(str)).thenReturn(id);
Boleto b = mock(Boleto.class);
Optional<Boleto> bo = Optional.of(b);
when(boletoRepository.findById(1)).thenReturn(bo);
BoletoVO bvo = mock(BoletoVO.class);
when(boletoMapper.mapToVO(b)).thenReturn(bvo);
BoletoVO bvo1 = boletoService.listById(str);
verify(uuidProvider).isValid(str);
verify(uuidProvider).fromString(str);
@Autowired
private BoletoService boletoService;
@MockBean
private BoletoRepository
boletoRepository;
@MockBean
private BoletoMapper boletoMapper;
@MockBean
private UUIDProvider uuidProvider;
Setup test
PERGUNTAS?
Referências
● https://blog.cleancoder.com/uncle-bob/2014/05/14/TheLittleMocker.html
● https://github.com/testdouble/contributing-tests/wiki/Detroit-school-TDD
● https://github.com/testdouble/contributing-tests/wiki/London-school-TDD
● http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
● http://codemanship.co.uk/parlezuml/blog/?postid=987
● http://thedevengers.com/tdd-triangulation/
● https://en.wikipedia.org/wiki/Test_double
● https://www.futurelearn.com/info/blog/stubs-mocks-spies-rspec
● https://pt.stackoverflow.com/questions/36745

TDD Primeiro Contato

  • 1.
  • 2.
    { “Nome” : “GuilhermeBotossi”, “Profissão” : “Software Engineer”, “Empresa” : “Creditas” “Mercados” : [ “Fiscal”, “Varejista”, “Financeiro”, “Educacional”, “Pesquisa Cientifica” ], “Redes_Sociais” : { “Github”: “@guilhermebotossi”, “Linkedin” : “@guilhermebotossi”, “Instagram” : “@guilhermebotossi” } }
  • 3.
    O que éTDD? ● Test Driven Development. ● Metodologia de desenvolvimento baseado em testes. ● Os testes unitários são escritos antes da funcionalidade.
  • 4.
    Tipos de testese distribuição: CustoeComplexidade
  • 5.
    O que éTeste Unitario? Um teste unitário(de uma unidade) é o teste da menor parte testável de um programa. A unidade pode ser uma instrução, método, classe, funcionalidade e etc. Depende muito do que é a menor parte que seu software pode ser testado. Cada teste deve ser responsável por testar apenas um comportamento
  • 6.
    O Teste unitáriodeve ser (F.I.R.S.T.) ● Fast ⇒ Rápido; ● Independent ⇒ Independente; ● Repeatable ⇒ Repetitivo; ● Self-Verifiable ⇒ Auto-Verificável; ● Timily ⇒ Escrito no momento certo;
  • 7.
    O que éTeste de Integração? É o teste utilizando os recursos reais sem assistência de test doubles, ou seja ele garante que tudo funciona conforme testado.
  • 8.
    Se eu tenhotestes unitários, por que eu preciso de testes de Integração?
  • 9.
    Como Funciona As 3Leis do TDD O desenvolvimento deve ser orientado por essas 3 leis: 1. You are not allowed to write any production code unless it is to make a failing unit test pass. 2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures. 3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test. Essas 3 leis em resumo fazem alusão ao uso de “Baby Steps”. Robert C. Martin aka Uncle Bob
  • 10.
    Ciclo de Desenvolvimentode Testes Unitários 1 - RED - Erro nos teste; 2 - GREEN - Corrigir o erro no teste ou corrigir o teste, da maneira mais fácil possível ; 3 - REFACTOR - Limpar a casa, uma vez que seu teste passou, agora você pode pensar na melhor maneira de fazer;
  • 11.
    Formato do Teste Temosos 3 A’s : ● Arrange - É a preparação, seja de ambiente, variáveis, banco de dados, test doubles e etc. Tudo aquilo que o teste irá utilizar. ● Act - Realizamos a chamada do SUT(System Under Test) ● Assert - É o momento de verificarmos se o teste trouxe os resultados esperados.
  • 12.
    Vantagens ● Evita futureproofing(?) ● Garante consistência ● Evita desperdícios ● Refatoração em ambiente seguro ● Os testes são uma documentação ● Reduz esforços de retrabalho
  • 13.
  • 14.
    Desvantagens ● Tempo dedesenvolvimento* ● Testes devem ser mantidos ● Deve ser um esforço de time ● Difícil ser aplicado em código legados ● No início tem custo alto no desenvolvimento ● Refatorações, requerem também a refatoração dos testes
  • 15.
    O que elenão garante? ● Código livre de bugs ● Qualidade ● Ausência de Erros
  • 16.
  • 17.
    Dummy ● São Placeholders,geralmente eles são usados apenas para preencher listas de parâmetros. ● Poderia ser substituido por Null ● São objetos que não interagem diretamente com o SUT ● O conteúdo não é relevante, mas o objeto é obrigatório @Test public void addCustomerTest() { //método privado no teste pra criar um customer qualquer //Customer customer = createDummyCustomer(); //Ou Customer dummy = mock(Customer.class); AddressBook addressBook = new AddressBook(); addressBook.addCustomer(customer); assertEquals(1, addressBook.getNumberOfCustomers()); }
  • 18.
    Stub ● Fornecem respostaspré configuradas às chamadas feitas durante o teste. ● Podemos usar para testar o caminho feliz e os casos com exceção public class AcceptingAuthorizerStub implements Authorizer { public Boolean authorize(String username, String password) { return true; } } EntityManager entityManager = mock(EntityManager.class); when(entityManager.find(Customer.class,1L)).thenReturn(sampleCustomer);
  • 19.
    Spy ● Spies sãoStubs que registram informações de suas iterações. ● Podendo ou não ser a chamada do método real @Test public void whenStubASpy_thenStubbed() { List<String> list = new ArrayList<String>(); List<String> spyList = Mockito.spy(list); assertEquals(0, spyList.size()); Mockito.doReturn(100).when(spyList).size(); assertEquals(100, spyList.size()); } @Test public void whenSpyingOnList_thenCorrect() { List<String> list = new ArrayList<String>(); List<String> spyList = Mockito.spy(list); spyList.add("one"); spyList.add("two"); Mockito.verify(spyList).add("one"); Mockito.verify(spyList).add("two"); assertEquals(2, spyList.size()); }
  • 20.
    Mock ● Mocks sãoobjetos configurados, onde define-se o comportamento das chamadas esperadas durante o teste. ● Podem lançar uma exceção se receberem uma chamada que não configurada ● Permite verificação dos comportamentos configurados UUIDProvider uuidProvider = mock(UUIDProvider.class) when(uuidProvider.isValid(uuid)).thenReturn(true); UUID id = UUID.fromString(uuid); when(uuidProvider.fromString(str)).thenReturn(id); verify(uuidProvider).isValid(str); verify(uuidProvider).fromString(str);
  • 21.
    Fake ● É umaimplementação real, voltada para os testes e que não será usada em produção ● Tem um comportamento voltado regras de negócio ● Podem ser extremamente complexos ● Normalmente representam um serviço externo, tal qual um banco de dado, ou um sistema de autenticação. public class AcceptingAuthorizerFake implements Authorizer { public Boolean authorize(String username, String password) { return username.equals("Bob"); } }
  • 22.
  • 23.
    Escolas de TDD Classicist(Detroit) ● Bottom-up / Middle-out ● Teste da API pública ● Avanço através de pequenos incrementos ● Liberdade para refatorações agressivas na implementação ● Chances de criar um YAGNI ● Testes Superficiais, foco no resultado ● Teste de Regressão em uma única suíte ● Testa estado Mockist (London) ● Top-down ● Teste de todas as camadas ● Alto acoplamento entre testes e implementação ● Reescrever ao invés de re-fatorar ● Design Limpo e minimalista ● Grande quantidade de test doubles ● Teste regressão depende de mais de uma suíte ● Testa Comportamento
  • 24.
    System Under Test(SUT) publicBoletoVO listById(String id) { if(uuidProvider.isValid(id)) { UUID uuid = uuidProvider.fromString(id); Optional<Boleto> bo = boletoRepository.findById(uuid); if(bo.isPresent()) { return boletoMapper.mapToVO(bo.get()); } else { throw new BankslipRecordNotFoundException(); } } throw new InvalidUUIDFormatException(); }
  • 25.
    @Test public void listById_called_returnOK(){ String uuid = "8c9f029f-53d2-4f75-8cf5- 75a13c4046e3"; BoletoVO bvo = boletoService.listById(uuid); assertNotNull(bvo); assertEquals(uuid, bvo.getId().toString()); @Autowired private BoletoService boletoService; @Autowired @Qualifier(“fakeBoletoRepository”) private BoletoRepository boletoRepository; Exemplo-Classicist
  • 26.
    Exemplo-Mockist @Test public voidlistById_called_returnOK() { String uuid = "8c9f029f-53d2-4f75-8cf5- 75a13c4046e3"; when(uuidProvider.isValid(uuid)).thenReturn(true); UUID id = UUID.fromString(uuid); when(uuidProvider.fromString(str)).thenReturn(id); Boleto b = mock(Boleto.class); Optional<Boleto> bo = Optional.of(b); when(boletoRepository.findById(1)).thenReturn(bo); BoletoVO bvo = mock(BoletoVO.class); when(boletoMapper.mapToVO(b)).thenReturn(bvo); BoletoVO bvo1 = boletoService.listById(str); verify(uuidProvider).isValid(str); verify(uuidProvider).fromString(str); @Autowired private BoletoService boletoService; @MockBean private BoletoRepository boletoRepository; @MockBean private BoletoMapper boletoMapper; @MockBean private UUIDProvider uuidProvider; Setup test
  • 29.
  • 30.
    Referências ● https://blog.cleancoder.com/uncle-bob/2014/05/14/TheLittleMocker.html ● https://github.com/testdouble/contributing-tests/wiki/Detroit-school-TDD ●https://github.com/testdouble/contributing-tests/wiki/London-school-TDD ● http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd ● http://codemanship.co.uk/parlezuml/blog/?postid=987 ● http://thedevengers.com/tdd-triangulation/ ● https://en.wikipedia.org/wiki/Test_double ● https://www.futurelearn.com/info/blog/stubs-mocks-spies-rspec ● https://pt.stackoverflow.com/questions/36745

Notas do Editor

  • #6 http://tdd.caelum.com.br/ https://martinfowler.com/articles/mocksArentStubs.html https://www.devmedia.com.br/test-driven-development-tdd-simples-e-pratico/18533
  • #17 https://medium.com/trainingcenter/testes-unit%C3%A1rios-mocks-stubs-spies-e-todas-essas-palavras-dif%C3%ADceis-f2765ac87cc8 https://klauslaube.com.br/2015/06/29/os-testes-e-os-dubles-parte-2.html https://martinfowler.com/articles/mocksArentStubs.html https://martinfowler.com/bliki/TestDouble.html https://hipsters.tech/testes-automatizados-hipsters-51/
  • #24 https://agilewarrior.wordpress.com/2015/04/18/classical-vs-mockist-testing/ https://stackoverflow.com/questions/3464629/what-does-regression-test-mean