Trimmed the example to showcase an unit-test for a simple exception-handler
authorKai Moritz <kai@juplo.de>
Sat, 3 Oct 2020 14:49:23 +0000 (16:49 +0200)
committerKai Moritz <kai@juplo.de>
Sat, 3 Oct 2020 14:55:12 +0000 (16:55 +0200)
pom.xml
src/main/java/de/juplo/demo/ExampleController.java
src/main/java/de/juplo/demo/ExampleService.java
src/main/resources/templates/view.html
src/test/java/de/juplo/demo/ExceptionHandlingApplicationIT.java [deleted file]
src/test/java/de/juplo/demo/ExceptionHandlingApplicationTests.java

diff --git a/pom.xml b/pom.xml
index 546ac9f..09a4f3e 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                                </exclusion>
                        </exclusions>
                </dependency>
-               <dependency>
-                       <groupId>org.jsoup</groupId>
-                       <artifactId>jsoup</artifactId>
-                       <version>1.13.1</version>
-                       <scope>test</scope>
-               </dependency>
-               <dependency>
-                       <groupId>org.springframework.boot</groupId>
-                       <artifactId>spring-boot-starter-webflux</artifactId>
-                       <scope>test</scope>
-               </dependency>
        </dependencies>
 
        <build>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                        </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-failsafe-plugin</artifactId>
-                       </plugin>
                </plugins>
        </build>
 
index a6efeb2..6c49f6b 100644 (file)
@@ -6,11 +6,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.servlet.DispatcherServlet;
 import org.springframework.web.servlet.ModelAndView;
-import org.thymeleaf.exceptions.TemplateProcessingException;
-
-import java.util.Optional;
 
 @Controller
 public class ExampleController
@@ -34,9 +30,7 @@ public class ExampleController
             Model model
     )
     {
-        Optional<Boolean> outcome =
-                answer == null ? null : service.checkAnswer(answer);
-
+        Boolean outcome = answer == null ? null : service.checkAnswer(answer);
         model.addAttribute("answer", answer);
         model.addAttribute("outcome", outcome);
         return "view";
@@ -51,31 +45,5 @@ public class ExampleController
         mav.addObject("exception", e);
         return mav;
     }
-
-    /**
-     * This {@link ExceptionHandler @ExceptionHander} is never triggered,
-     * because the exception is not thrown inside the controller:
-     * <strong>It is functionless!</strong>
-     * <p>
-     *     The exception is thrown by Thymeleaf, which is called by the
-     *     {@link DispatcherServlet} after the controller has finished its
-     *     work during the rendering of the outcome.
-     * </p>
-     * <p>
-     *     {@link ExceptionHandler @ExceptionHander's} are not able, to catch
-     *     and resolve exceptions, which are thrown outside of the scope of the
-     *     controller.
-     *     This is also true for {@link ControllerAdvice}.
-     * </p>
-     */
-    @ResponseStatus(HttpStatus.BAD_REQUEST)
-    @ExceptionHandler(TemplateProcessingException.class)
-    public ModelAndView templateInputException(TemplateProcessingException e)
-    {
-        LOG.error("{}: {}", HttpStatus.BAD_REQUEST, e.getMessage());
-        ModelAndView mav = new ModelAndView("400");
-        mav.addObject("exception", e);
-        return mav;
-    }
 }
 
index 45f2ca1..a638ea3 100644 (file)
@@ -2,25 +2,20 @@ package de.juplo.demo;
 
 import org.springframework.stereotype.Component;
 
-import java.util.Optional;
-
 @Component
 public class ExampleService
 {
-    public Optional<Boolean> checkAnswer(int answer)
+    public Boolean checkAnswer(int answer)
     {
-        if (answer < 0)
-            return Optional.empty();
-
         if (answer == 42)
         {
-            return Optional.of(true);
+            return true;
         }
         else
         {
             if (answer % 7 == 0)
                 throw new IllegalArgumentException(answer + " is devidable by 7!");
-            return Optional.of(false);
+            return false;
         }
     }
 }
index e632398..c862d36 100644 (file)
@@ -13,7 +13,7 @@
       </p>
       <ul th:case="*">
         <li>Presented answer: <strong th:text="${answer}">ANSWER</strong></li>
-        <li>Outcome: <strong th:text="${outcome.get()}">OUTCOME</strong></li>
+        <li>Outcome: <strong th:text="${outcome}">OUTCOME</strong></li>
       </ul>
     </div>
     <div class="card-text">
diff --git a/src/test/java/de/juplo/demo/ExceptionHandlingApplicationIT.java b/src/test/java/de/juplo/demo/ExceptionHandlingApplicationIT.java
deleted file mode 100644 (file)
index d964e6c..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-package de.juplo.demo;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.reactive.server.WebTestClient;
-
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.*;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureWebTestClient
-class ExceptionHandlingApplicationIT {
-       private final static Logger LOG =
-                       LoggerFactory.getLogger(ExceptionHandlingApplicationIT.class);
-
-       @MockBean
-       ExampleService service;
-
-       @Autowired
-       WebTestClient client;
-
-
-       @Test
-       void contextLoads() throws Exception {
-       }
-
-       @Test
-       void test200ForNoAnswer() throws Exception {
-               client
-                               .get()
-                               .uri("/")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isOk()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForEmptyAnswer() throws Exception {
-               client
-                               .get()
-                               .uri("/?answer= ")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isOk()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForAnswerThatContainsOnlyWhitespace() throws Exception {
-               client
-                               .get()
-                               .uri("/?answer=")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isOk()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForWrongAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.of(false));
-
-               client
-                               .get()
-                               .uri("/?answer=1234")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isOk()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("ul > li:nth-child(2) > strong").text()).isEqualTo("false");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForCorrectAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.of(true));
-
-               client
-                               .get()
-                               .uri("/?answer=1234")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isOk()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("ul > li:nth-child(2) > strong").text()).isEqualTo("true");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void testExceptionForNegativeAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.empty());
-
-               client
-                               .get()
-                               .uri("/?answer=1234")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("title").text())
-                                                       .isEqualTo("500: Internal Server Error");
-                                       assertThat(doc.selectFirst("div > p > strong").text())
-                                                       .isEqualTo("Catched exception: java.lang.IllegalArgumentException: FOO!");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test400ForStringInput() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.empty());
-
-               client
-                               .get()
-                               .uri("/?answer=bar")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isBadRequest()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("title").text())
-                                                       .isEqualTo("400: NumberFormatException");
-                                       assertThat(doc.selectFirst("div > p > strong").text())
-                                                       .isEqualTo("Catched exception: java.lang.NumberFormatException: For input string: \"bar\"");
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test400ForExceptionInBusinessLogic() throws Exception {
-               when(service.checkAnswer(anyInt())).thenThrow(new IllegalArgumentException("FOO!"));
-
-               client
-                               .get()
-                               .uri("/?answer=1234")
-                               .accept(MediaType.TEXT_HTML)
-                               .exchange()
-                               .expectStatus().isBadRequest()
-                               .expectBody(String.class).value(content -> {
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("title").text())
-                                                       .isEqualTo("400: IllegalArgumentException");
-                                       assertThat(doc.selectFirst("div > p > strong").text())
-                                                       .isEqualTo("Catched exception: java.lang.IllegalArgumentException: FOO!");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-}
index 62f3a13..77eb7f6 100644 (file)
@@ -1,30 +1,20 @@
 package de.juplo.demo;
 
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
 import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.web.util.NestedServletException;
 
 import java.net.URI;
-import java.util.Optional;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.*;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 @WebMvcTest(ExampleController.class)
 class ExceptionHandlingApplicationTests {
-       private final static Logger LOG =
-                       LoggerFactory.getLogger(ExceptionHandlingApplicationTests.class);
 
        @MockBean
        ExampleService service;
@@ -33,129 +23,13 @@ class ExceptionHandlingApplicationTests {
        MockMvc mvc;
 
 
-       @Test
-       void contextLoads() throws Exception {
-       }
-
-       @Test
-       void test200ForNoAnswer() throws Exception {
-               mvc
-                               .perform(get(URI.create("http://FOO/")))
-                               .andExpect(status().isOk())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForEmptyAnswer() throws Exception {
-               mvc
-                               .perform(get(URI.create("http://FOO/?answer=")))
-                               .andExpect(status().isOk())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForAnswerThatContainsOnlyWhitespace() throws Exception {
-               mvc
-                               .perform(get(URI.create("http://FOO/?answer=%20")))
-                               .andExpect(status().isOk())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.select("ul > li")).isEmpty();
-                               });
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForWrongAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.of(false));
-
-               mvc
-                               .perform(get(URI.create("http://FOO/?answer=1234")))
-                               .andExpect(status().isOk())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("ul > li:nth-child(2) > strong").text()).isEqualTo("false");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test200ForCorrectAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.of(true));
-
-               mvc
-                               .perform(get(URI.create("http://FOO/?answer=1234")))
-                               .andExpect(status().isOk())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("ul > li:nth-child(2) > strong").text()).isEqualTo("true");
-                               });
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void testExceptionForNegativeAnswer() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.empty());
-
-               // The corrected version of the test catches the wrapper NestedServletException
-               // for exceptions, that are handled in the DispatcherServlet in a fully setup
-               // and, hence, cannot be handled in a @WebMvcTest, that mocks this part of the stack.
-               assertThrows(
-                               NestedServletException.class,
-                               () -> mvc.perform(get(URI.create("http://FOO/?answer=1234"))));
-
-               verify(service, times(1)).checkAnswer(anyInt());
-       }
-
-       @Test
-       void test400ForStringInput() throws Exception {
-               when(service.checkAnswer(anyInt())).thenReturn(Optional.empty());
-
-               // The expected behaviour of the following test is, that the WhiteLabel Error Page
-               // is rendered, for the unallowed string-value.
-               // Instead, an almost empty page is rendered for the error.
-               mvc
-                               .perform(get(URI.create("http://FOO/?answer=bar")))
-                               .andExpect(status().isBadRequest());
-                               // Specifying exceptations for the rendered output is not useful,
-                               // because MockMvc does not render the White Label ErrorPage
-
-               verify(service, times(0)).checkAnswer(anyInt());
-       }
-
        @Test
        void test400ForExceptionInBusinessLogic() throws Exception {
                when(service.checkAnswer(anyInt())).thenThrow(new IllegalArgumentException("FOO!"));
 
                mvc
                                .perform(get(URI.create("http://FOO/?answer=1234")))
-                               .andExpect(status().isBadRequest())
-                               .andDo((result) -> {
-                                       String content = result.getResponse().getContentAsString();
-                                       Document doc = Jsoup.parse(content);
-                                       assertThat(doc.selectFirst("title").text())
-                                                       .isEqualTo("400: IllegalArgumentException");
-                                       assertThat(doc.selectFirst("div > p > strong").text())
-                                                       .isEqualTo("Catched exception: java.lang.IllegalArgumentException: FOO!");
-                               });
+                               .andExpect(status().isBadRequest());
 
                verify(service, times(1)).checkAnswer(anyInt());
        }