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 via Devconf(Opensanca)

Por que testes de unidade não são suficientes para seus microsserviços via Devconf(Opensanca)

Rafael Ponte, aborda sobre a ineficácia de Testes Unitários para garantir total qualidade em Microserviços.

Sinopse:
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).

Opensanca

May 27, 2023
Tweet

More Decks by Opensanca

Other Decks in Programming

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 full-size slide

  2. Quase 20 anos de estrada

    View full-size slide

  3. Mas foi em 2004…

    View full-size slide

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

    View full-size slide

  5. O cenário melhorou

    View full-size slide

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

    View full-size slide

  7. Ainda escrevemos testes ruins.

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  11. Em que proporção?

    View full-size slide

  12. O problema de falar dos tipos
    de testes…

    View full-size slide

  13. Por isso vamos nos
    entender aqui!

    View full-size slide

  14. browser
    app


    (servidor)
    banco de dados

    View full-size slide

  15. teste de unidade
    browser
    app


    (servidor)
    banco de dados

    View full-size slide

  16. teste de integração
    browser
    app


    (servidor)
    banco de dados

    View full-size slide

  17. teste de aceitação

    View full-size slide

  18. banco de dados
    app


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

    View full-size slide

  19. Voltando para piramide…

    View full-size slide

  20. Mas vieram outras…

    View full-size slide

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

    View full-size slide

  22. Qual devo seguir?
    Qual a melhor?

    View full-size slide

  23. O que todas
    procuram….

    View full-size slide

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

    View full-size slide

  25. Menos percentual; Mais qualidade;

    View full-size slide

  26. Mobile
    Monolith

    View full-size slide

  27. Microservices
    Mobile
    Monolith

    View full-size slide

  28. Microservices

    View full-size slide

  29. Quando eu falo de microservices…

    View full-size slide

  30. Base de código pequena

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  33. O problema é que…

    View full-size slide

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

    View full-size slide

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

    then lower-level tests
    aren't needed.”

    View full-size slide

  36. Calma lá…

    View full-size slide

  37. O que eu quero dizer é…

    View full-size slide

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

    View full-size slide

  39. Focar em Qualidade

    View full-size slide

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

    View full-size slide

  41. “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 full-size slide

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

    View full-size slide

  43. Microservices

    View full-size slide

  44. navegador
    servidor

    View full-size slide

  45. navegador
    servidor
    requisição

    View full-size slide

  46. navegador
    servidor db
    requisição

    View full-size slide

  47. navegador
    servidor db
    requisição
    resposta

    View full-size slide

  48. navegador
    servidor db
    requisição
    resposta

    View full-size slide

  49. @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 full-size slide

  50. @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 full-size slide

  51. @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 full-size slide

  52. @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 full-size slide

  53. @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 full-size slide

  54. @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 full-size slide

  55. @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 full-size slide

  56. @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 full-size slide

  57. @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 full-size slide

  58. @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 full-size slide

  59. @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 full-size slide

  60. @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 full-size slide

  61. @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 full-size slide

  62. @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 full-size slide

  63. @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 full-size slide

  64. @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 full-size slide

  65. Hora dos testes

    View full-size slide

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

    View full-size slide

  67. 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 full-size slide

  68. 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 full-size slide

  69. 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 full-size slide

  70. 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 full-size slide

  71. 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 full-size slide

  72. 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 full-size slide

  73. 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 full-size slide

  74. 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 full-size slide

  75. 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 full-size slide

  76. 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 full-size slide

  77. 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 full-size slide

  78. 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 full-size slide

  79. 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 full-size slide

  80. 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 full-size slide

  81. 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 full-size slide

  82. 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 full-size slide

  83. 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 full-size slide

  84. 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 full-size slide

  85. 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 full-size slide

  86. 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 full-size slide

  87. 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 full-size slide

  88. 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 full-size slide

  89. 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 full-size slide

  90. 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 full-size slide

  91. 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 full-size slide

  92. 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 full-size slide

  93. 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 full-size slide

  94. 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 full-size slide

  95. 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 full-size slide

  96. 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 full-size slide

  97. 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 full-size slide

  98. 1.2 segundos

    View full-size slide

  99. Linha não coberta!

    View full-size slide

  100. Precisamos entrar no if()!

    View full-size slide

  101. Caminho
    alternativo

    View full-size slide

  102. 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 full-size slide

  103. 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 full-size slide

  104. 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 full-size slide

  105. 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 full-size slide

  106. 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 full-size slide

  107. 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 full-size slide

  108. 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 full-size slide

  109. 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 full-size slide

  110. 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 full-size slide

  111. 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 full-size slide

  112. 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 full-size slide

  113. 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 full-size slide

  114. 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 full-size slide

  115. 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 full-size slide

  116. 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 full-size slide

  117. 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 full-size slide

  118. 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 full-size slide

  119. 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 full-size slide

  120. 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 full-size slide

  121. 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 full-size slide

  122. 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 full-size slide

  123. 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 full-size slide

  124. 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 full-size slide

  125. 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 full-size slide

  126. 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 full-size slide

  127. 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 full-size slide

  128. 1.2 segundos

    View full-size slide

  129. Posso mandar para produção? 😈

    View full-size slide

  130. @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 full-size slide

  131. @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 full-size slide

  132. @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 full-size slide

  133. @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 full-size slide

  134. @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 full-size slide

  135. @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 full-size slide

  136. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  137. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  138. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  139. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  140. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  141. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  142. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  143. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  144. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  145. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  146. Mais uma vez…

    View full-size slide

  147. @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 full-size slide

  148. @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 full-size slide

  149. @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 full-size slide

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

    View full-size slide

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

    View full-size slide

  152. CONFIANÇA
    Aumentar a con
    fi

    View full-size slide

  153. Não foi por falta de aviso!

    View full-size slide

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

    then lower-level tests
    aren't needed.”

    View full-size slide

  155. “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 full-size slide

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

    View full-size slide

  157. Rafael Ponte


    @rponte

    View full-size slide

  158. Fortaleza - Terra do Sol

    View full-size slide

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

    View full-size slide

  160. Nosso código

    View full-size slide

  161. @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 full-size slide

  162. Vamos cobri-lo com testes…

    View full-size slide

  163. Testes de Integração?


    Não há consenso

    View full-size slide

  164. Mais próximo da produção

    View full-size slide

  165. navegador
    servidor db
    requisição
    resposta

    View full-size slide

  166. navegador
    servidor db
    requisição
    resposta

    View full-size slide

  167. navegador
    servidor db
    requisição
    resposta

    View full-size slide

  168. Hora dos testes

    View full-size slide

  169. @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 full-size slide

  170. @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 full-size slide

  171. @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 full-size slide

  172. @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 full-size slide

  173. @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 full-size slide

  174. @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 full-size slide

  175. @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 full-size slide

  176. @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 full-size slide

  177. @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 full-size slide

  178. @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 full-size slide

  179. @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 full-size slide

  180. @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 full-size slide

  181. @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 full-size slide

  182. @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 full-size slide

  183. @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 full-size slide

  184. @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 full-size slide

  185. @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 full-size slide

  186. @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 full-size slide

  187. @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 full-size slide

  188. @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 full-size slide

  189. @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 full-size slide

  190. @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 full-size slide

  191. @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 full-size slide

  192. @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 full-size slide

  193. @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 full-size slide

  194. @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 full-size slide

  195. @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 full-size slide

  196. O que rolou
    por baixo dos
    panos…

    View full-size slide

  197. Posso mandar para produção? 😈

    View full-size slide

  198. Caminho
    alternativo

    View full-size slide

  199. 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 full-size slide

  200. 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 full-size slide

  201. 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 full-size slide

  202. 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 full-size slide

  203. 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 full-size slide

  204. 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 full-size slide

  205. 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 full-size slide

  206. 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 full-size slide

  207. 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 full-size slide

  208. 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 full-size slide

  209. 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 full-size slide

  210. Posso mandar para produção? 😈

    View full-size slide

  211. @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 full-size slide

  212. @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 full-size slide

  213. @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 full-size slide

  214. @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 full-size slide

  215. public class NovoLivroRequest {


    @ISBN


    @NotBlank


    private String isbn;


    @NotBlank


    private String titulo;


    @Past


    @NotNull


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  216. public class NovoLivroRequest {


    @ISBN


    @NotBlank


    private String isbn;


    @NotBlank


    private String titulo;


    @Past


    @NotNull


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  217. Caminho
    alternativo
    #2

    View full-size slide

  218. 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 full-size slide

  219. 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 full-size slide

  220. 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 full-size slide

  221. 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 full-size slide

  222. 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 full-size slide

  223. 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 full-size slide

  224. 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 full-size slide

  225. 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 full-size slide

  226. 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 full-size slide

  227. 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 full-size slide

  228. 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 full-size slide

  229. 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 full-size slide

  230. 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 full-size slide

  231. 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 full-size slide

  232. 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 full-size slide

  233. 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 full-size slide

  234. Posso mandar para produção? 😈

    View full-size slide

  235. @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 full-size slide

  236. @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 full-size slide

  237. @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 full-size slide

  238. @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 full-size slide

  239. 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 full-size slide

  240. 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 full-size slide

  241. Vamos de novo…

    View full-size slide

  242. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  243. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

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

    View full-size slide

  245. A aplicação nem sobe!

    View full-size slide

  246. Eu poderia continuar…

    View full-size slide

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

    View full-size slide

  248. Posso mandar para produção? 😈

    View full-size slide

  249. …estivessemos
    num contexto
    critico

    View full-size slide

  250. @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 full-size slide

  251. @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 full-size slide

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

    View full-size slide

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


    {


    isbn: “ABC-123”,


    titulo: “Livro X”,


    publicadoEm: “2023-01-01”


    }

    View full-size slide

  254. 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 full-size slide

  255. 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 full-size slide

  256. 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 full-size slide

  257. select l.*


    from livro l

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  260. Temos um bug de
    RACE CONDITION

    View full-size slide

  261. Caminho
    alternativo
    #3

    View full-size slide

  262. 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 full-size slide

  263. 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 full-size slide

  264. 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 full-size slide

  265. 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 full-size slide

  266. 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 full-size slide

  267. 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 full-size slide

  268. 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 full-size slide

  269. 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 full-size slide

  270. 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 full-size slide

  271. 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 full-size slide

  272. Corrigimos o problema…

    View full-size slide

  273. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  274. @Entity


    class Livro {


    @Id


    @GeneratedValue(strategy = IDENTITY)


    private Long id;


    private String isbn;


    private String titulo;


    private LocalDate publicadoEm;


    // construtor, getters etc


    }

    View full-size slide

  275. @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 full-size slide

  276. alter table livro


    add constraint uk_isbn


    unique (isbn);

    View full-size slide

  277. Rodamos o teste novamente…

    View full-size slide

  278. https://speakerdeck.com/jordihofc

    View full-size slide

  279. Não foi uma palestra sobre…

    View full-size slide

  280. Nem sobre…

    View full-size slide

  281. Mas sim sobre qualidade

    View full-size slide

  282. “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 full-size slide

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

    View full-size slide

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

    View full-size slide

  285. E para isso temos que abraçar
    nosso framework

    View full-size slide

  286. Estude e pratique.

    Fique bom na escrita de testes

    View full-size slide

  287. https://www.mauricioaniche.com/books

    View full-size slide

  288. https://rieckpil.de/
    https://www.mauricioaniche.com/books

    View full-size slide

  289. Ainda duvida?

    View full-size slide

  290. @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 full-size slide

  291. Te desa
    fi
    o!!
    😈

    View full-size slide

  292. @rponte
    Rafael Ponte

    View full-size slide