-------------------------------------------------------------------------------- /src/main/resources/templates/index.mustache: -------------------------------------------------------------------------------- 1 | {{>header}} 2 |
3 |
4 |

Spring WebFlux And Kotlin example

5 |

This example is a quick exercise to illustrate how to build a web application with Spring 5 6 | reactive stack and Kotlin language.

7 | View it on Github 8 |
9 |
10 |
11 |
12 | {{#posts}} 13 |
14 |
15 |
16 |

{{title}}

17 |
{{createdDate}}
18 |

{{content}}

19 | View Details 20 |
21 |
22 |
23 | {{/posts}} 24 |
25 |
26 | {{>footer}} 27 | -------------------------------------------------------------------------------- /src/test/kotlin/com/example/demo/ApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.DisplayName 5 | import org.junit.jupiter.api.Test 6 | import org.junit.jupiter.api.TestInfo 7 | 8 | 9 | class ApplicationTests { 10 | 11 | @Test 12 | @DisplayName("My 1st JUnit 5 test! 😎") 13 | fun `my first Junit 5 test`(testInfo: TestInfo) { 14 | assertEquals(2, 1 + 1, "1 + 1 should equal 2") 15 | assertEquals("My 1st JUnit 5 test! 😎", testInfo.displayName) { "TestInfo is injected correctly" } 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/example/demo/IntegrationTests.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import org.junit.jupiter.api.AfterAll 4 | import org.junit.jupiter.api.BeforeAll 5 | import org.junit.jupiter.api.Test 6 | import org.springframework.http.MediaType.* 7 | import org.springframework.web.reactive.function.client.WebClient 8 | import org.springframework.web.reactive.function.client.bodyToFlux 9 | import org.springframework.web.reactive.function.client.bodyToMono 10 | import reactor.test.test 11 | import java.time.LocalDateTime 12 | 13 | class IntegrationTests { 14 | 15 | private val application = Application(8181) 16 | private val client = WebClient.create("http://localhost:8181") 17 | 18 | @BeforeAll 19 | fun beforeAll() { 20 | application.start() 21 | } 22 | 23 | @Test 24 | fun `Find all posts on JSON REST endpoint`() { 25 | client.get().uri("/api/posts") 26 | .accept(APPLICATION_JSON) 27 | .retrieve() 28 | .bodyToFlux() 29 | .test() 30 | .expectNextMatches { it.title == "Post one" && it.content == "content of Post one" && it.createdDate.isBefore(LocalDateTime.now()) } 31 | .expectNextMatches { it.title == "Post two" && it.content == "content of Post two" && it.createdDate.isBefore(LocalDateTime.now()) } 32 | .verifyComplete() 33 | } 34 | 35 | @Test 36 | fun `Find all posts on HTML page`() { 37 | client.get().uri("/") 38 | .accept(TEXT_HTML) 39 | .retrieve() 40 | .bodyToMono() 41 | .test() 42 | .expectNextMatches { it.contains("Post one") && it.contains("Post two") } 43 | .verifyComplete() 44 | } 45 | 46 | @Test 47 | fun `Receive a stream of posts via stream json `() { 48 | client.get().uri("/api/posts") 49 | .accept(APPLICATION_STREAM_JSON) 50 | .retrieve() 51 | .bodyToFlux() 52 | .test() 53 | .expectNextMatches { it.title == "Post one" && it.content == "content of Post one" && it.createdDate.isBefore(LocalDateTime.now()) } 54 | .expectNextMatches { it.title == "Post two" && it.content == "content of Post two" && it.createdDate.isBefore(LocalDateTime.now()) } 55 | .expectNextMatches { it.title == "Post one" && it.content == "content of Post one" && it.createdDate.isBefore(LocalDateTime.now()) } 56 | .expectNextMatches { it.title == "Post two" && it.content == "content of Post two" && it.createdDate.isBefore(LocalDateTime.now()) } 57 | .thenCancel() 58 | .verify() 59 | } 60 | 61 | @Test 62 | fun `Receive a stream of posts via SSE `() { 63 | client.get().uri("/api/posts") 64 | .accept(TEXT_EVENT_STREAM) 65 | .retrieve() 66 | .bodyToFlux() 67 | .test() 68 | .expectNextMatches { it.title == "Post one" && it.content == "content of Post one" && it.createdDate.isBefore(LocalDateTime.now()) } 69 | .expectNextMatches { it.title == "Post two" && it.content == "content of Post two" && it.createdDate.isBefore(LocalDateTime.now()) } 70 | .expectNextMatches { it.title == "Post one" && it.content == "content of Post one" && it.createdDate.isBefore(LocalDateTime.now()) } 71 | .expectNextMatches { it.title == "Post two" && it.content == "content of Post two" && it.createdDate.isBefore(LocalDateTime.now()) } 72 | .thenCancel() 73 | .verify() 74 | } 75 | 76 | @AfterAll 77 | fun afterAll() { 78 | application.stop() 79 | } 80 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/example/demo/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.demo 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class UtilsTest{ 7 | 8 | @Test 9 | fun `slugify string "Post one" should return "post-one"`() { 10 | assertEquals("post-one", "Post one".slugify()) 11 | } 12 | } -------------------------------------------------------------------------------- /src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.testinstance.lifecycle.default = per_class 2 | --------------------------------------------------------------------------------