Phil as a nice post about the improvements on testing in Spring Boot 1.4, check it out here: Testing improvements in Spring Boot 1.4.
I’d like to add a concrete example for those and some more, please have a look at the comments inside one of the most important controllers I’ve ever written 😉
Those are the dependencies you’ll need for the demo:
<dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>org.springframework.restdocs</groupid> <artifactid>spring-restdocs-mockmvc</artifactid> <scope>test</scope> </dependency> </dependencies> |
Here’s the complete demo application:
import java.io.IOException; import java.io.PrintStream; import javax.servlet.http.HttpServletResponse; import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.core.env.Environment; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @SpringBootApplication public class Demo14Application { @Controller @RequestMapping("/api/banner") static class BannerController { // 1) If you didn't chose to disable banner in your application (and why // should you? ;) ), the banner will be availabe as a bean in your // application // 2) banner.jpg :) You can replace banner.txt with a banner.jpg or banner.png // to generate some nice ascii art during startup private final Banner banner; private final Environment environment; // 3) no more @Autowired on constructors necessary // when there's on a unique non-default constructor // This also works on @Configuration classes, which didn't support // constructor injection at all so far. // This comes actually from Spring Framework 4.3.RC1 public BannerController(final Banner banner, final Environment environment) { this.banner = banner; this.environment = environment; } // 4) More annotations ;) // Precomposed @GetMapping, @PostMapping, @RequestScope, @SessionScope etc @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public void get(final HttpServletResponse response) throws IOException { try (PrintStream printStream = new PrintStream(response.getOutputStream())) { banner.printBanner(environment, BannerController.class, printStream); } } } public static void main(String[] args) { SpringApplication.run(Demo14Application.class, args); } } |
And here’s the test. I really like the simplifications there:
import BannerController; import java.io.PrintStream; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.Banner; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.doAnswer; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; // 5) Easier named JUnit Runner ;) @RunWith(SpringRunner.class) // 6) Test slices of your application, in this case the Spring MVC slice // similiar options are available for @DataJpaTest and @JsonTest (incuding // JacksonTester). @WebMvcTest(controllers = BannerController.class) // 7) Together with the above auto configuration comes autoconfiguration of // Spring REST docs, which removes the need for the JUnit rule and additional // configuration of the mock mvc instance // BTW: It seams that you can use addtitional formats like markdown for the // snippets @AutoConfigureRestDocs( outputDir = "target/generated-snippets", uriHost = "banner-as-a-service.io", uriPort = 80 ) public class Demo14ApplicationTests { // 8) Spring Boot includes a @MockBean annotation that can be used to define // a Mockito mock for a bean inside your ApplicationContext. You can use // the annotation to add new beans, or replace a single existing bean // definition. @MockBean private Banner banner; @Autowired private MockMvc mockMvc; @Test public void testSomeMethod() throws Exception { doAnswer(invocation -> { final PrintStream out = invocation.getArgumentAt(2, PrintStream.class); out.write(bannerText.getBytes()); return null; }).when(banner).printBanner(anyObject(), anyObject(), anyObject()); mockMvc .perform( get("/api/banner").accept(APPLICATION_JSON) ) .andExpect(status().isOk()) .andExpect(content().string(bannerText)) .andDo(document("api/banner", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); } private final String bannerText = " _____ _ ______ _____ _____ _____ _ \n" + "/ ___| (_) | ___ \\ ___/ ___|_ _| | | \n" + "\\ `--. _ __ _ __ _ _ __ __ _ | |_/ / |__ \\ `--. | | __| | ___ ___ ___ \n" + " `--. \\ '_ \\| '__| | '_ \\ / _` | | /| __| `--. \\ | | / _` |/ _ \\ / __/ __|\n" + "/\\__/ / |_) | | | | | | | (_| | | |\\ \\| |___/\\__/ / | | | (_| | (_) | (__\\__ \\\n" + "\\____/| .__/|_| |_|_| |_|\\__, | \\_| \\_\\____/\\____/ \\_/ \\__,_|\\___/ \\___|___/\n" + " | | __/ | \n" + " |_| |___/ \n" + " _ _ _ ___ _____ _____ _____ _____ _ \n" + " (_) | | | / _ \\ / ___/ __ \\_ _|_ _| | | \n" + "__ ___| |_| |__ / /_\\ \\\\ `--.| / \\/ | | | | __ _ _ __| |_ \n" + "\\ \\ /\\ / / | __| '_ \\ | _ | `--. \\ | | | | | / _` | '__| __| \n" + " \\ V V /| | |_| | | | | | | |/\\__/ / \\__/\\_| |_ _| |_ | (_| | | | |_ \n" + " \\_/\\_/ |_|\\__|_| |_| \\_| |_/\\____/ \\____/\\___/ \\___/ \\__,_|_| \\__| \n" + " \n" + " "; } |
Have a look at the release notes or the updated reference documentation for more.
Thanks Josh for including my silly example in This Week in Spring once more, i love it:
No comments yet
One Trackback/Pingback
[…] our other pal Michael Simons is back at it again this week, also with a look at the features in Spring Boot 1.4 […]
Post a Comment