Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Por que testes de unidade não são suficientes para seus microsserviços

Por que testes de unidade não são suficientes para seus microsserviços

Sem dúvida a adoção de microsserviços possibilitou que empresas com dezenas ou centenas de times pudessem colocar software em produção de forma isolada e independente, em ritmos distintos sem que um time pisasse no pé do outro. Contudo, não podemos ignorar que apesar das vantagens organizacionais trazidas por esse estilo arquitetural, tivemos que abraçar sua complexidade inerente que, em essência, saiu do código e foi parar nas bordas.

O que eu quero dizer, é que mesmo pequenas lógicas de negócio deixaram de ser chamadas locais em memória dentro de um mesmo processo e passaram a ser chamadas remotas entre serviços numa rede instável por natureza. Garantir que estas lógicas funcionam como esperado deixou de ser uma tarefa simples, e confiar apenas nos testes de unidade pode ser perigoso e um erro sem volta.

Nesta palestra, pretendo discutir por que testes de unidade sozinhos não são adequados para garantir a corretude do seu código, nem para revelar bugs mais cedo ou mesmo para permitir a evolução da sua aplicação de forma segura e sustentável. Não à toa, vamos entender por que favorecer a escrita de testes de integração e abraçar as facilidades do seu framework IoC/DI pode ser crucial para o desenvolvimento, manutenção e entrega de qualidade dos seus microsserviços.

Se você confia que seus testes de unidade são suficientes, então essa palestra é para você, caro desenvolvedor(a).

Rafael Ponte

May 27, 2023
Tweet

More Decks by Rafael Ponte

Other Decks in Technology

Transcript

  1. Favoreça testes de integração
    …ou por que testes de unidade não são su
    fi
    cientes para seus microservices

    View Slide

  2. Quase 20 anos de estrada

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. Mas foi em 2004…

    View Slide

  11. Em 2004…
    https://twitter.com/rponte/status/1502616694384168963?s=20

    View Slide

  12. O cenário melhorou

    View Slide

  13. As vezes eu acho que muitos
    devs(as) estudam sobre testes
    tanto quanto estudam sobre Jira 😬

    View Slide

  14. Ainda escrevemos testes ruins.

    View Slide

  15. Mas não dá para culpar
    somente o dev(a)…

    View Slide

  16. Unit
    Integration
    Acceptance
    Performance
    Scalability
    Security
    Exploratory Contract
    End-to-End
    Accessibility
    Mutant
    Load Stress

    View Slide

  17. Unit
    Integration
    Performance
    Scalability
    Security
    Exploratory Contract
    Accessibility
    Mutant
    Load Stress
    Acceptance
    End-to-End

    View Slide

  18. Em que proporção?

    View Slide

  19. View Slide

  20. O problema de falar dos tipos
    de testes…

    View Slide

  21. View Slide

  22. View Slide

  23. View Slide

  24. Por isso vamos nos
    entender aqui!

    View Slide

  25. View Slide

  26. browser
    app


    (servidor)
    banco de dados

    View Slide

  27. teste de unidade
    browser
    app


    (servidor)
    banco de dados

    View Slide

  28. teste de integração
    browser
    app


    (servidor)
    banco de dados

    View Slide

  29. teste de aceitação

    View Slide

  30. banco de dados
    app


    (servidor)
    teste de integração
    teste de unidade
    teste de aceitação
    browser

    View Slide

  31. Voltando para piramide…

    View Slide

  32. View Slide

  33. View Slide

  34. View Slide

  35. Mas vieram outras…

    View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. "A Simpler Testing Pyramid"
    https://www.infoq.com/articles/testing-pyramid-slow-fast-tests/

    View Slide

  41. Qual devo seguir?
    Qual a melhor?

    View Slide

  42. GUIAS

    View Slide

  43. View Slide

  44. View Slide

  45. O que todas
    procuram….

    View Slide

  46. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  47. Menos percentual; Mais qualidade;

    View Slide

  48. View Slide

  49. Monolith

    View Slide

  50. Mobile
    Monolith

    View Slide

  51. Microservices
    Mobile
    Monolith

    View Slide

  52. Microservices

    View Slide

  53. Quando eu falo de microservices…

    View Slide

  54. Base de código pequena

    View Slide

  55. Base de código pequena
    Pouca lógica de negócio

    View Slide

  56. Base de código pequena
    Pouca lógica de negócio
    Muito I/O e pouca computação

    View Slide

  57. O problema é que…

    View Slide

  58. View Slide

  59. O cenário mudou, a tecnologia evoluiu.

    View Slide

  60. — Martin Fowler
    “If my high level tests are
    fast, reliable, and cheap to
    modify -

    then lower-level tests
    aren't needed.”

    View Slide

  61. Calma lá…

    View Slide

  62. View Slide

  63. O que eu quero dizer é…

    View Slide

  64. View Slide

  65. https://engineering.atspotify.com/2018/01/testing-of-microservices/

    View Slide

  66. Focar em Qualidade

    View Slide

  67. “As long as you are focusing on
    fast, easy-to-be-written, with good
    feedback tests, you are
    fi
    ne.”

    View Slide

  68. “As long as you are focusing on
    fast, easy-to-be-written, with good
    feedback tests, you are
    fi
    ne.”
    https://e
    ff
    ectivesoftwaretesting.substack.com/p/unit-or-integration-tests

    View Slide

  69. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  70. Livraria

    View Slide

  71. Microservices

    View Slide

  72. View Slide

  73. View Slide

  74. View Slide

  75. servidor

    View Slide

  76. servidor

    View Slide

  77. navegador
    servidor

    View Slide

  78. navegador
    servidor
    requisição

    View Slide

  79. navegador
    servidor db
    requisição

    View Slide

  80. navegador
    servidor db
    requisição
    resposta

    View Slide

  81. navegador
    servidor db
    requisição
    resposta

    View Slide

  82. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  83. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  84. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  85. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  86. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  87. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  88. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  89. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  90. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  91. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  92. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  93. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }
    Injetado pelo
    Spring!

    View Slide

  94. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  95. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  96. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  97. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  98. Hora dos testes

    View Slide

  99. Mas antes de irmos para
    os nossos queridos testes
    de integração…

    View Slide

  100. View Slide

  101. Happy-path

    View Slide

  102. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  103. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  104. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  105. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  106. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  107. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  108. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  109. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  110. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  111. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  112. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  113. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  114. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  115. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  116. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  117. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  118. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    Mockito

    View Slide

  119. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  120. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  121. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  122. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  123. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  124. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  125. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  126. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  127. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }
    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    View Slide

  128. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  129. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  130. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  131. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  132. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    “Design e Arquitetura Java",


    LocalDate.now().plusDays(1));


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(false);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseEntity> response = controller.cadastra(request);


    // validação


    assertEquals(HttpStatus.CREATED, response.getStatusCode());


    }


    }

    View Slide

  133. View Slide

  134. View Slide

  135. 1.2 segundos

    View Slide

  136. View Slide

  137. Linha não coberta!

    View Slide

  138. Precisamos entrar no if()!

    View Slide

  139. Caminho
    alternativo

    View Slide

  140. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  141. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  142. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  143. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  144. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  145. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  146. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  147. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  148. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  149. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  150. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  151. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  152. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  153. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  154. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  155. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  156. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  157. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  158. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(repository.existsByIsbn(“978-0-4703-2225-3")).thenReturn(true);


    View Slide

  159. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(repository.existsByIsbn(“978-0-4703-2225-3")).thenReturn(true);


    View Slide

  160. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(repository.existsByIsbn(“978-0-4703-2225-3")).thenReturn(true);


    View Slide

  161. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(repository.existsByIsbn(“978-0-4703-2225-3")).thenReturn(true);


    View Slide

  162. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(repository.existsByIsbn(“978-0-4703-2225-3")).thenReturn(true);


    View Slide

  163. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }
    when(/** ... */).thenReturn( );


    true

    View Slide

  164. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  165. class NovoLivroControllerTest {


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() { /** ... */ }


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Outro livro de Arquitetura Java",


    LocalDate.now());


    LivroRepository repository = mock(LivroRepository.class);


    when(repository.existsByIsbn("978-0-4703-2225-3")).thenReturn(true);


    // ação


    NovoLivroController controller = new NovoLivroController(repository);


    ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> {


    controller.cadastra(request);


    });


    // validação


    assertEquals("livro já existente", exception.getReason());


    }


    }

    View Slide

  166. View Slide

  167. View Slide

  168. 1.2 segundos

    View Slide

  169. View Slide

  170. View Slide

  171. Uhuull!

    View Slide

  172. Posso mandar para produção? 😈

    View Slide

  173. E se…

    View Slide

  174. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  175. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  176. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  177. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }
    Desligamos a
    validação do
    Spring! 👀

    View Slide

  178. 🤔
    💭

    View Slide

  179. View Slide

  180. View Slide

  181. 🤯

    View Slide

  182. E se…

    View Slide

  183. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  184. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  185. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  186. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  187. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  188. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  189. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  190. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  191. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  192. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  193. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  194. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  195. View Slide

  196. View Slide

  197. 😱

    View Slide

  198. Mais uma vez…

    View Slide

  199. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  200. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  201. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  202. View Slide

  203. View Slide

  204. 🤡

    View Slide

  205. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  206. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  207. CONFIANÇA
    Aumentar a con
    fi

    View Slide

  208. Não foi por falta de aviso!

    View Slide

  209. — Martin Fowler
    “If my high level tests are
    fast, reliable, and cheap to
    modify -

    then lower-level tests
    aren't needed.”

    View Slide

  210. View Slide

  211. “As long as you are focusing on
    fast, easy-to-be-written, with good
    feedback tests, you are
    fi
    ne.”
    https://e
    ff
    ectivesoftwaretesting.substack.com/p/unit-or-integration-tests

    View Slide

  212. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  213. View Slide

  214. Rafael Ponte


    @rponte

    View Slide

  215. View Slide

  216. Fortaleza - Terra do Sol

    View Slide

  217. View Slide

  218. Favoreça testes de integração
    …ou por que testes de unidade não são su
    fi
    cientes para seus microservices

    View Slide

  219. Nosso código

    View Slide

  220. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  221. Vamos cobri-lo com testes…

    View Slide

  222. View Slide

  223. Testes de Integração?


    Não há consenso

    View Slide

  224. View Slide

  225. Mais próximo da produção

    View Slide

  226. navegador
    servidor db
    requisição
    resposta

    View Slide

  227. navegador
    servidor db
    requisição
    resposta

    View Slide

  228. navegador
    servidor db
    requisição
    resposta

    View Slide

  229. View Slide

  230. Hora dos testes

    View Slide

  231. Happy-path

    View Slide

  232. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  233. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  234. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  235. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  236. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  237. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  238. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  239. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  240. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  241. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  242. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());
    @Autowired


    protected MockMvc mockMvc;

    View Slide

  243. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  244. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  245. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  246. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  247. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  248. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  249. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());
    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );

    View Slide

  250. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  251. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());

    View Slide

  252. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  253. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  254. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }
    Efeito
    colateral!

    View Slide

  255. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  256. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  257. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  258. @SpringBootTest


    @ActiveProfiles("test")


    @AutoConfigureMockMvc(printOnlyOnFailure = false)


    class NovoLivroControllerIntegrationTest {


    @Autowired


    private LivroRepository repository;


    @Autowired


    protected MockMvc mockMvc;


    @Autowired


    private ObjectMapper mapper;


    @BeforeEach


    public void setUp() {


    repository.deleteAll();


    }


    @Test


    @DisplayName("deve cadastrar novo livro")


    public void t1() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  259. View Slide

  260. Uhuull!

    View Slide

  261. O que rolou
    por baixo dos
    panos…

    View Slide

  262. View Slide

  263. Posso mandar para produção? 😈

    View Slide

  264. Caminho
    alternativo

    View Slide

  265. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  266. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  267. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  268. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  269. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  270. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  271. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  272. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  273. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  274. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  275. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando livro já existente")


    public void t2() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // grava livro no banco


    repository.save(request.toModel());


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isUnprocessableEntity())


    .andExpect(jsonPath("$.detail", is("livro já existente”)));


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  276. View Slide

  277. Posso mandar para produção? 😈

    View Slide

  278. Não!

    View Slide

  279. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  280. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  281. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }
    Validação!

    View Slide

  282. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  283. public class NovoLivroRequest {


    @ISBN


    @NotBlank


    private String isbn;


    @NotBlank


    private String titulo;


    @Past


    @NotNull


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  284. public class NovoLivroRequest {


    @ISBN


    @NotBlank


    private String isbn;


    @NotBlank


    private String titulo;


    @Past


    @NotNull


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  285. Caminho
    alternativo
    #2

    View Slide

  286. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  287. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  288. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  289. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  290. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  291. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  292. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  293. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  294. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  295. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  296. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  297. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  298. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  299. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  300. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  301. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  302. View Slide

  303. Uhuull!

    View Slide

  304. Posso mandar para produção? 😈

    View Slide

  305. E se…

    View Slide

  306. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  307. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  308. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  309. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }
    Desligamos a
    validação do
    Spring! 👀

    View Slide

  310. View Slide

  311. View Slide

  312. View Slide

  313. View Slide

  314. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  315. class NovoLivroControllerIntegrationTest {


    // atributos, outros métodos de teste e @BeforeEach


    @Test


    @DisplayName("não deve cadastrar novo livro quando parametros invalidos")


    public void t3() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    “978-0-INVA-LID-XX",


    "",


    LocalDate.now().plusDays(1)


    );


    // ação


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isBadRequest())


    .andExpect(jsonPath("$.violations", hasSize(3)))


    .andExpect(jsonPath("$.violations", containsInAnyOrder(


    violation("isbn", "invalid ISBN"),


    violation("titulo", "must not be blank"),


    violation("publicadoEm", "must be a past date")


    )


    ));


    // validação


    assertEquals(0, repository.count());


    }


    }

    View Slide

  316. Vamos de novo…

    View Slide

  317. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  318. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  319. View Slide

  320. View Slide

  321. View Slide

  322. Vocês não estão entendendo…

    View Slide

  323. A aplicação nem sobe!

    View Slide

  324. Eu poderia continuar…

    View Slide

  325. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  326. Posso mandar para produção? 😈

    View Slide

  327. E se…

    View Slide

  328. …estivessemos
    num contexto
    critico

    View Slide

  329. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  330. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  331. Aplicação
    Usuário 1 Usuário 2

    View Slide

  332. Aplicação
    Usuário 1 Usuário 2
    POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    }

    View Slide

  333. Aplicação
    Usuário 1 Usuário 2
    POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    } POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    }

    View Slide

  334. Aplicação
    Usuário 1 Usuário 2
    HTTP 201
    (CREATED)
    POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    } POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    }

    View Slide

  335. Aplicação
    Usuário 1 Usuário 2
    HTTP 201
    (CREATED)
    HTTP 201
    (CREATED)
    POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    } POST /api/livros


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    }

    View Slide

  336. select l.*


    from livro l

    View Slide

  337. ID ISBN TITULO PUBLICADO_EM
    1001 ... ... ...
    1002 ABC-123 Livro X 2023-01-01
    1003 ABC-123 Livro X 2023-01-01
    1004 ... ... ...

    View Slide

  338. ID ISBN TITULO PUBLICADO_EM
    1001 ... ... ...
    1002 ABC-123 Livro X 2023-01-01
    1003 ABC-123 Livro X 2023-01-01
    1004 ... ... ...

    View Slide

  339. Ooops!

    View Slide

  340. Temos um bug de
    RACE CONDITION

    View Slide

  341. Caminho
    alternativo
    #3

    View Slide

  342. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  343. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  344. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  345. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  346. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  347. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  348. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }
    Número de
    usuários
    concorrentes!

    View Slide

  349. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  350. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  351. class NovoLivroControllerIntegrationTest {


    // atributos


    @Test


    @DisplayName("não deve cadastrar novo livro repetido quando em alta-concorrência")


    public void t4() throws Exception {


    // cenário


    NovoLivroRequest request = new NovoLivroRequest(


    "978-0-4703-2225-3",


    "Design e Arquitetura Java",


    LocalDate.now().minusMonths(6)


    );


    // ação


    doSyncAndConcurrently(10, s -> {


    String json = toJson(request);


    mockMvc.perform(post("/api/livros")


    .contentType(MediaType.APPLICATION_JSON)


    .content(json))


    .andExpect(status().isCreated());


    });


    // validação


    assertEquals(1, repository.count());


    }


    }

    View Slide

  352. View Slide

  353. View Slide

  354. View Slide

  355. Corrigimos o problema…

    View Slide

  356. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  357. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  358. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    @Column(unique = true)


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View Slide

  359. alter table livro


    add constraint uk_isbn


    unique (isbn);

    View Slide

  360. Rodamos o teste novamente…

    View Slide

  361. View Slide

  362. Uhuull!

    View Slide

  363. https://speakerdeck.com/jordihofc

    View Slide

  364. E claro…

    View Slide

  365. View Slide

  366. CONCLUINDO

    View Slide

  367. Não foi uma palestra sobre…

    View Slide

  368. View Slide

  369. Nem sobre…

    View Slide

  370. View Slide

  371. Mas sim sobre qualidade

    View Slide

  372. “As long as you are focusing on
    fast, easy-to-be-written, with good
    feedback tests, you are
    fi
    ne.”
    https://e
    ff
    ectivesoftwaretesting.substack.com/p/unit-or-integration-tests

    View Slide

  373. CONFIANÇA
    Aumentar a con
    fi
    ança minimizando os custos

    View Slide

  374. View Slide

  375. Base de código pequena
    Pouca lógica de negócio
    Muito I/O e pouca computação

    View Slide

  376. View Slide

  377. E para isso temos que abraçar
    nosso framework

    View Slide

  378. View Slide

  379. Estude e pratique.

    Fique bom na escrita de testes

    View Slide

  380. https://www.mauricioaniche.com/books

    View Slide

  381. https://rieckpil.de/
    https://www.mauricioaniche.com/books

    View Slide

  382. Ainda duvida?

    View Slide

  383. @RestController


    public class NovoLivroController {


    private final LivroRepository repository;


    @Transactional


    @PostMapping("/api/livros")


    public ResponseEntity> cadastra(@RequestBody @Valid NovoLivroRequest request) {


    if (repository.existsByIsbn(request.getIsbn())) {


    throw new ResponseStatusException(UNPROCESSABLE_ENTITY, “livro já existente”);


    }


    Livro livro = request.toModel();


    repository.save(livro);


    return ResponseEntity


    .status(CREATED).build();


    }


    }

    View Slide

  384. Te desa
    fi
    o!!
    😈

    View Slide

  385. @rponte
    Rafael Ponte

    View Slide