Skip to content

Commit 9a490ba

Browse files
add junit tests
1 parent 4608498 commit 9a490ba

File tree

8 files changed

+246
-75
lines changed

8 files changed

+246
-75
lines changed

build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ dependencies {
4242
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
4343
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4444

45+
// test utils
46+
testImplementation 'io.projectreactor:reactor-test'
47+
testImplementation 'io.mockk:mockk:1.13.12'
48+
testImplementation 'com.ninja-squad:springmockk:4.0.2'
49+
50+
// wiremock
51+
testImplementation 'org.wiremock:wiremock-standalone:3.9.1'
52+
4553
// monitoring
4654
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
4755
implementation 'org.springframework.boot:spring-boot-starter-actuator'

src/main/kotlin/com/softeno/template/app/permission/api/PermissionController.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.apache.commons.logging.LogFactory
88
import org.springframework.context.ApplicationEventPublisher
99
import org.springframework.data.domain.Page
1010
import org.springframework.http.ResponseEntity
11+
import org.springframework.validation.annotation.Validated
1112
import org.springframework.web.bind.annotation.DeleteMapping
1213
import org.springframework.web.bind.annotation.GetMapping
1314
import org.springframework.web.bind.annotation.PathVariable
@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestParam
1819
import org.springframework.web.bind.annotation.RestController
1920

2021
@RestController
22+
@Validated
2123
class PermissionController(
2224
private val permissionService: PermissionService,
2325
private val applicationEventPublisher: ApplicationEventPublisher

src/main/kotlin/com/softeno/template/sample/http/external/api/ExternalController.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package com.softeno.template.sample.http.external.api
33
import com.softeno.template.sample.http.external.client.ExternalServiceClient
44
import org.apache.commons.logging.LogFactory
55
import org.springframework.http.ResponseEntity
6+
import org.springframework.validation.annotation.Validated
67
import org.springframework.web.bind.annotation.GetMapping
78
import org.springframework.web.bind.annotation.PathVariable
89
import org.springframework.web.bind.annotation.RequestMapping
910
import org.springframework.web.bind.annotation.RestController
1011

1112
@RestController
1213
@RequestMapping("/external")
14+
@Validated
1315
class ExternalController(
1416
private val externalServiceClient: ExternalServiceClient
1517
) {

src/test/groovy/com/softeno/template/app/permission/api/PermissionITSpec.groovy

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package com.softeno.template.app
2+
3+
import com.github.tomakehurst.wiremock.WireMockServer
4+
import com.github.tomakehurst.wiremock.client.WireMock.*
5+
import com.github.tomakehurst.wiremock.client.WireMock.aResponse
6+
import com.github.tomakehurst.wiremock.client.WireMock.urlMatching
7+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options
8+
import com.ninjasquad.springmockk.MockkBean
9+
import com.softeno.template.SoftenoMvcJpaApp
10+
import com.softeno.template.app.permission.PermissionFixture.Companion.aPermission
11+
import com.softeno.template.app.permission.PermissionFixture.Companion.aPermissionDto
12+
import com.softeno.template.app.permission.db.PermissionRepository
13+
import io.mockk.every
14+
import org.junit.jupiter.api.AfterEach
15+
import org.junit.jupiter.api.Assertions.assertEquals
16+
import org.junit.jupiter.api.Assertions.assertTrue
17+
import org.junit.jupiter.api.BeforeEach
18+
import org.junit.jupiter.api.Test
19+
import org.springframework.beans.factory.annotation.Autowired
20+
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
21+
import org.springframework.boot.context.properties.EnableConfigurationProperties
22+
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
23+
import org.springframework.boot.test.context.SpringBootTest
24+
import org.springframework.core.Ordered
25+
import org.springframework.core.annotation.Order
26+
import org.springframework.data.domain.PageImpl
27+
import org.springframework.data.domain.Pageable
28+
import org.springframework.kafka.test.context.EmbeddedKafka
29+
import org.springframework.test.web.reactive.server.WebTestClient
30+
import org.springframework.web.reactive.function.BodyInserters
31+
import org.springframework.web.reactive.function.client.WebClient
32+
import org.testcontainers.containers.PostgreSQLContainer
33+
import org.testcontainers.junit.jupiter.Container
34+
import org.testcontainers.junit.jupiter.Testcontainers
35+
36+
@Testcontainers
37+
@SpringBootTest(
38+
classes = [SoftenoMvcJpaApp::class],
39+
properties = ["spring.profiles.active=integration"],
40+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
41+
)
42+
@AutoConfigureWebTestClient(timeout = "6000")
43+
@EnableConfigurationProperties
44+
@EmbeddedKafka(partitions = 1, brokerProperties = ["listeners=PLAINTEXT://localhost:9092", "port=9092"])
45+
@ConfigurationPropertiesScan("com.softeno")
46+
abstract class BaseIntegrationTest {
47+
48+
@Autowired
49+
lateinit var permissionRepository: PermissionRepository
50+
51+
@Autowired
52+
lateinit var webTestClient: WebTestClient
53+
54+
@Container
55+
var postgreSQLContainer = PostgreSQLContainer("postgres:15.2-alpine")
56+
.withDatabaseName("application")
57+
.withUsername("admin")
58+
.withPassword("admin")
59+
60+
61+
@BeforeEach
62+
fun init() {
63+
// ...
64+
}
65+
66+
@AfterEach
67+
fun cleanup() {
68+
permissionRepository.deleteAll()
69+
}
70+
71+
}
72+
73+
class ContextLoadsTest : BaseIntegrationTest() {
74+
75+
@Test
76+
fun testConnection() {
77+
assertTrue(postgreSQLContainer.isRunning)
78+
}
79+
}
80+
81+
class PermissionTest : BaseIntegrationTest() {
82+
83+
@Test
84+
fun shouldReturnEmptyPermissionResponse() {
85+
webTestClient.get().uri("/permissions")
86+
.exchange()
87+
.expectStatus().isOk()
88+
.expectBody().jsonPath("content").isEmpty
89+
}
90+
91+
@Test
92+
fun shouldRetrievePermission() {
93+
val aPermission = aPermission()
94+
permissionRepository.save(aPermission)
95+
96+
webTestClient.get().uri("/permissions")
97+
.exchange()
98+
.expectStatus().isOk()
99+
.expectBody()
100+
.jsonPath("content.[0].name").isEqualTo(aPermission.name!!)
101+
.jsonPath("content.[0].description").isEqualTo(aPermission.description!!)
102+
}
103+
104+
@Test
105+
fun shouldPersistPermission() {
106+
val aPermissionDto = aPermissionDto()
107+
108+
webTestClient.post().uri("/permissions")
109+
.body(BodyInserters.fromValue(aPermissionDto))
110+
.exchange()
111+
.expectStatus().isOk
112+
113+
assertEquals(permissionRepository.findAll().size, 1)
114+
assertEquals(permissionRepository.findAll()[0].name!!, aPermissionDto.name)
115+
assertEquals(permissionRepository.findAll()[0].description!!, aPermissionDto.description)
116+
}
117+
}
118+
119+
class PermissionTestMockk : BaseIntegrationTest() {
120+
121+
@MockkBean
122+
@Order(value = Ordered.HIGHEST_PRECEDENCE)
123+
lateinit var permissionRepositoryMock: PermissionRepository
124+
125+
@BeforeEach
126+
fun initMockkRepository() {
127+
every { permissionRepositoryMock.deleteAll() }.answers { }
128+
}
129+
130+
@Test
131+
fun shouldPersistAndRetrievePermission() {
132+
val aPermission = aPermission()
133+
134+
every { permissionRepositoryMock.findAll(any<Pageable>()) }.answers { PageImpl(listOf(aPermission)) }
135+
136+
webTestClient.get().uri("/permissions")
137+
.exchange()
138+
.expectStatus().isOk()
139+
.expectBody()
140+
.jsonPath("content.[0].name").isEqualTo(aPermission.name!!)
141+
.jsonPath("content.[0].description").isEqualTo(aPermission.description!!)
142+
}
143+
}
144+
145+
data class SampleResponseDto(val data: String)
146+
147+
class ExternalControllerTest : BaseIntegrationTest(), ExternalApiAbility {
148+
149+
@Autowired
150+
private lateinit var webclient: WebClient
151+
152+
private val wiremock: WireMockServer = WireMockServer(options().port(4500))
153+
154+
@BeforeEach
155+
fun `setup wiremock`() {
156+
wiremock.start()
157+
}
158+
159+
@AfterEach
160+
fun `stop wiremock`() {
161+
wiremock.stop()
162+
wiremock.resetAll()
163+
}
164+
165+
@Test
166+
fun `mock external service with wiremock`() {
167+
// given
168+
mockGetId(wiremock)
169+
170+
val expected = SampleResponseDto(data = "1")
171+
172+
// expect
173+
val response = webclient.get().uri("http://localhost:4500/sample/100")
174+
.retrieve()
175+
.bodyToMono(SampleResponseDto::class.java)
176+
.block()
177+
178+
assertEquals(expected, response)
179+
}
180+
181+
@Test
182+
fun `test external controller`() {
183+
// given
184+
mockGetId(wiremock)
185+
186+
// expect
187+
webTestClient.get().uri("/external/1")
188+
.exchange()
189+
.expectStatus().isOk()
190+
.expectBody()
191+
.jsonPath("data").isEqualTo("1")
192+
}
193+
}
194+
195+
interface ExternalApiAbility {
196+
197+
fun mockGetId(wiremock: WireMockServer) {
198+
wiremock.stubFor(
199+
get(urlMatching("/sample/.*"))
200+
.willReturn(
201+
aResponse()
202+
.withStatus(200)
203+
.withHeader("Content-Type", "application/json")
204+
.withBody(
205+
"""
206+
{
207+
"data": "1"
208+
}
209+
""".trimIndent()
210+
)
211+
)
212+
)
213+
}
214+
}
215+
216+

src/test/kotlin/com/softeno/template/app/config/TestRestTemplateConfig.kt

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/test/kotlin/com/softeno/template/app/permission/PermissionFixture.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,23 @@ import com.softeno.template.app.permission.mapper.PermissionDto
55
class PermissionFixture {
66
companion object {
77
@JvmStatic
8-
fun somePermissionDto(name: String, description: String) = PermissionDto(name = name, description = description,
8+
fun aPermission(name: String = "some permission", description: String = "some description"): Permission {
9+
val permission = Permission()
10+
permission.id = null
11+
permission.createdDate = null
12+
permission.createdBy = null
13+
permission.modifiedBy = null
14+
permission.modifiedDate = null
15+
permission.version = null
16+
permission.name = name
17+
permission.description = description
18+
19+
return permission
20+
}
21+
22+
23+
@JvmStatic
24+
fun aPermissionDto(name: String = "some permission", description: String = "some description") = PermissionDto(name = name, description = description,
925
id = null, version = null, createdBy = null, createdDate = null, modifiedBy = null, modifiedDate = null)
1026
}
1127
}

src/test/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ spring.application.name=SoftenoJpaPostgresApp
33

44
### custom: external services
55

6-
com.softeno.external.url=http://localhost:4500
6+
com.softeno.external.url=http://localhost:4500/sample
77
com.softeno.external.name=node-service
88

99
com.softeno.kafka.tx=sample_topic_2

0 commit comments

Comments
 (0)