Skip to content

Commit 8b787a5

Browse files
2. Demo for integration testing with docker compose starter completed
1 parent 1df8ea8 commit 8b787a5

File tree

8 files changed

+217
-1
lines changed

8 files changed

+217
-1
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
Репозиторий содержит исходные коды проектов, которые используются в следующих видео:
44

5+
## Интеграционное тестирование | Spring Boot + Yandex SourceCraft + Amplicode + Docker Compose Starter
6+
7+
* Видео: https://youtu.be/suqpDTeHqSY
8+
* Проект: [app](integration-testing-docker-compose/app)
9+
* Инструкция для самостоятельного прохождения демо-сценария: [README.md](integration-testing-docker-compose/app)
10+
511
## Новый HTTP-клиент от Amplicode на Kotlin Script для Spring-приложений и не только
612

713
* Видео: https://youtu.be/P-aN3GuWYvo
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Интеграционное тестирование | Spring Boot + Yandex SourceCraft + Amplicode + Docker Compose Starter
2+
3+
[![](https://i3.ytimg.com/vi/suqpDTeHqSY/maxresdefault.jpg)](https://youtu.be/suqpDTeHqSY)
4+
5+
Текущая директория содержит проект `app`, который был использован в видео.
6+
7+
Все действия производились в ветке `integration-testing-docker-compose`.
8+
9+
Первый коммит с которого можно начать повторять демо `1df8ea8a1722cf7b4fa530e3bacbdfe6b120cf8f`.

integration-testing-docker-compose/app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ dependencies {
2828
'jakarta.xml.bind:jakarta.xml.bind-api',
2929
'org.flywaydb:flyway-core',
3030
'org.flywaydb:flyway-database-postgresql',
31-
'org.springframework.kafka:spring-kafka'
31+
'org.springframework.kafka:spring-kafka',
32+
'org.springframework.boot:spring-boot-docker-compose'
3233
)
3334

3435
runtimeOnly (
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
services:
2+
postgres-test:
3+
extends:
4+
service: postgres
5+
file: services.yaml
6+
ports:
7+
- "5432:5432"
8+
environment:
9+
POSTGRES_PASSWORD: postgres
10+
POSTGRES_DB: postgres
11+
POSTGRES_USER: postgres
12+
kafka-test:
13+
extends:
14+
service: kafka
15+
file: services.yaml
16+
ports:
17+
- "9094:9094"
18+
environment:
19+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka-test:29094,PLAINTEXT_HOST://localhost:9094
20+
KAFKA_LISTENERS: PLAINTEXT://kafka-test:29094,PLAINTEXT_HOST://0.0.0.0:9094,CONTROLLER://kafka-test:9093
21+
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka-test:9093
22+
healthcheck:
23+
test: kafka-topics --bootstrap-server localhost:9094 --list
24+
interval: 10s
25+
timeout: 5s
26+
start_period: 30s
27+
retries: 5

integration-testing-docker-compose/app/src/main/resources/application.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ spring.datasource.driver-class-name=org.postgresql.Driver
3535

3636
# Maximum time static resources should be cached
3737
spring.web.resources.cache.cachecontrol.max-age=12h
38+
39+
spring.docker.compose.enabled=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package org.springframework.samples.petclinic.owner.rest;
2+
3+
import com.jayway.jsonpath.JsonPath;
4+
import org.junit.jupiter.api.Test;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.http.MediaType;
9+
import org.springframework.samples.petclinic.owner.Owner;
10+
import org.springframework.samples.petclinic.owner.OwnerRepository;
11+
import org.springframework.test.context.TestPropertySource;
12+
import org.springframework.test.context.jdbc.Sql;
13+
import org.springframework.test.web.servlet.MockMvc;
14+
import org.springframework.test.web.servlet.MvcResult;
15+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
16+
17+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
18+
import static org.hamcrest.Matchers.*;
19+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
20+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
21+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
22+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
23+
24+
/**
25+
* Test class for the {@link OwnerRestController}
26+
*/
27+
@SpringBootTest
28+
@TestPropertySource(properties = {
29+
"spring.docker.compose.enabled=true",
30+
"spring.docker.compose.skip.in-tests=false",
31+
"spring.docker.compose.stop.command=down",
32+
"spring.docker.compose.file=docker-compose-tests.yaml"
33+
})
34+
@AutoConfigureMockMvc
35+
public class OwnerRestControllerTest {
36+
37+
@Autowired
38+
private MockMvc mockMvc;
39+
40+
@Autowired
41+
private OwnerRepository ownerRepository;
42+
43+
@Test
44+
public void create() throws Exception {
45+
String ownerDto = """
46+
{
47+
"firstName": "John",
48+
"lastName": "Doe",
49+
"address": "123 Main St",
50+
"city": "New York",
51+
"telephone": "5551234567"
52+
}""";
53+
54+
MvcResult mvcResult = mockMvc.perform(post("/rest/owners")
55+
.content(ownerDto)
56+
.contentType(MediaType.APPLICATION_JSON))
57+
.andExpect(status()
58+
.isOk())
59+
.andExpect(jsonPath("$.id").isNumber())
60+
.andReturn();
61+
62+
String jsonResponse = mvcResult.getResponse()
63+
.getContentAsString();
64+
Integer id = JsonPath.parse(jsonResponse)
65+
.read("$.id");
66+
67+
ownerRepository.findById(id).orElseThrow();
68+
69+
ownerRepository.deleteById(id);
70+
}
71+
72+
@Test
73+
public void createIdNotNull() throws Exception {
74+
String ownerDto = """
75+
{
76+
"id": 1,
77+
"firstName": "John",
78+
"lastName": "Doe",
79+
"address": "123 Main St",
80+
"city": "New York",
81+
"telephone": "5551234567"
82+
}""";
83+
84+
mockMvc.perform(post("/rest/owners")
85+
.content(ownerDto)
86+
.contentType(MediaType.APPLICATION_JSON))
87+
.andExpect(status()
88+
.isUnprocessableEntity());
89+
}
90+
91+
@Test
92+
@Sql(scripts = "classpath:insert-owners.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
93+
@Sql(scripts = "classpath:delete-owners.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
94+
public void getOne() throws Exception {
95+
mockMvc.perform(get("/rest/owners/{0}", "1"))
96+
.andExpect(status()
97+
.isOk())
98+
.andExpect(jsonPath("$.id").value(1))
99+
.andExpect(jsonPath("$.firstName").value("John"))
100+
.andExpect(jsonPath("$.lastName").value("Doe"));
101+
}
102+
103+
@Test
104+
public void getOneNotFound() throws Exception {
105+
mockMvc.perform(get("/rest/owners/{id}", 0))
106+
.andExpect(status().isNotFound());
107+
}
108+
109+
@Test
110+
@Sql(scripts = "classpath:insert-owners.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
111+
@Sql(scripts = "classpath:delete-owners.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
112+
public void delete() throws Exception {
113+
mockMvc.perform(MockMvcRequestBuilders.delete("/rest/owners/{0}", "1"))
114+
.andExpect(status()
115+
.isOk())
116+
.andExpect(jsonPath("$.id").value(1))
117+
.andExpect(jsonPath("$.firstName").value("John"));
118+
119+
assertThat(ownerRepository.findById(1).isPresent()).isEqualTo(false);
120+
}
121+
122+
@Test
123+
@Sql(scripts = "classpath:insert-owners.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
124+
@Sql(scripts = "classpath:delete-owners.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
125+
public void patch() throws Exception {
126+
String patchNode = """
127+
{
128+
"id": 1,
129+
"firstName": "Johny",
130+
"address": null,
131+
"city": "Spring ville"
132+
}""";
133+
134+
mockMvc.perform(MockMvcRequestBuilders.patch("/rest/owners/{0}", "1")
135+
.content(patchNode)
136+
.contentType(MediaType.APPLICATION_JSON))
137+
.andExpect(status()
138+
.isOk())
139+
.andExpect(jsonPath("$.address").value(nullValue()))
140+
.andExpect(jsonPath("$.firstName").value("Johny"))
141+
.andExpect(jsonPath("$.lastName").value("Doe"))
142+
.andExpect(jsonPath("$.city").value("Spring ville"))
143+
.andExpect(jsonPath("$.telephone").value("555-123-4567"));
144+
145+
Owner owner = ownerRepository.findById(1).orElseThrow();
146+
147+
assertThat(owner.getAddress()).isNull();
148+
assertThat(owner.getFirstName()).isEqualTo("Johny");
149+
assertThat(owner.getCity()).isEqualTo("Spring ville");
150+
assertThat(owner.getTelephone()).isEqualTo("555-123-4567");
151+
assertThat(owner.getLastName()).isEqualTo("Doe");
152+
}
153+
154+
@Test
155+
@Sql(scripts = "classpath:insert-owners.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
156+
@Sql(scripts = "classpath:delete-owners.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
157+
public void getAll() throws Exception {
158+
mockMvc.perform(get("/rest/owners")
159+
.param("firstNameContains", "J"))
160+
.andExpect(status()
161+
.isOk())
162+
.andExpect(jsonPath("$.content[*].firstName").value(everyItem(startsWith("J"))))
163+
.andExpect(jsonPath("$.content.length()").value(2));
164+
}
165+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DELETE FROM owners where id in (1,2,3,4,5);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
INSERT INTO owners (id, first_name, last_name, address, city, telephone) VALUES ('1', 'John', 'Doe', '123 Main St', 'Anytown', '555-123-4567');
2+
INSERT INTO owners (id, first_name, last_name, address, city, telephone) VALUES ('2', 'Jane', 'Doe', '456 Oak Ave', 'Anytown', '555-234-5678');
3+
INSERT INTO owners (id, first_name, last_name, address, city, telephone) VALUES ('3', 'Bob', 'Smith', '789 Pine Ln', 'Anytown', '555-345-6789');
4+
INSERT INTO owners (id, first_name, last_name, address, city, telephone) VALUES ('4', 'Alice', 'Smith', '1011 Cedar Dr', 'Anytown', '555-456-7890');
5+
INSERT INTO owners (id, first_name, last_name, address, city, telephone) VALUES ('5', 'Charlie', 'Brown', '1213 Maple St', 'Anytown', '555-567-8901');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy