Skip to content

Commit 8319fd4

Browse files
committed
feat: acceptance-test
1 parent f56cb14 commit 8319fd4

File tree

7 files changed

+302
-2
lines changed

7 files changed

+302
-2
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<groupId>{{cookiecutter.group_id}}</groupId>
7+
<artifactId>{{cookiecutter.artifact_id}}-parent</artifactId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
<artifactId>acceptance-test</artifactId>
12+
<dependencies>
13+
<dependency>
14+
<groupId>{{cookiecutter.group_id}}</groupId>
15+
<artifactId>bootstrap</artifactId>
16+
</dependency>
17+
<!-- Important: DO NOT DELETE the below dependencies though might seem like redundant to that of
18+
bootstrap but they are required for jacoco and pitest report aggregation -->
19+
<!-- left adapter -->
20+
<dependency>
21+
<groupId>{{cookiecutter.group_id}}</groupId>
22+
<artifactId>rest-adapter</artifactId>
23+
</dependency>
24+
<!-- domain -->
25+
<dependency>
26+
<groupId>{{cookiecutter.group_id}}</groupId>
27+
<artifactId>domain</artifactId>
28+
</dependency>
29+
<!-- right adapter -->
30+
<dependency>
31+
<groupId>{{cookiecutter.group_id}}</groupId>
32+
<artifactId>jpa-adapter</artifactId>
33+
</dependency>
34+
<!-- Test -->
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-starter-test</artifactId>
38+
<scope>test</scope>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.h2database</groupId>
42+
<artifactId>h2</artifactId>
43+
</dependency>
44+
<!-- Cucumber dependencies -->
45+
<dependency>
46+
<groupId>io.cucumber</groupId>
47+
<artifactId>cucumber-java8</artifactId>
48+
<version>${cucumber.version}</version>
49+
<scope>test</scope>
50+
</dependency>
51+
<dependency>
52+
<groupId>io.cucumber</groupId>
53+
<artifactId>cucumber-junit-platform-engine</artifactId>
54+
<version>${cucumber.version}</version>
55+
<scope>test</scope>
56+
</dependency>
57+
<dependency>
58+
<groupId>io.cucumber</groupId>
59+
<artifactId>cucumber-spring</artifactId>
60+
<version>${cucumber.version}</version>
61+
<scope>test</scope>
62+
</dependency>
63+
</dependencies>
64+
<build>
65+
<plugins>
66+
<plugin>
67+
<groupId>com.github.cukedoctor</groupId>
68+
<artifactId>cukedoctor-maven-plugin</artifactId>
69+
<version>${cukedoctor-maven-plugin.version}</version>
70+
<configuration>
71+
<featuresDir>target/cucumber</featuresDir>
72+
<outputFileName>{{cookiecutter.domain_capitalized}}</outputFileName>
73+
<documentTitle>{{cookiecutter.domain_capitalized}} - Living Documentation</documentTitle>
74+
<docVersion>${project.version}</docVersion>
75+
<toc>center</toc>
76+
</configuration>
77+
<executions>
78+
<execution>
79+
<goals>
80+
<goal>execute</goal>
81+
</goals>
82+
<phase>verify</phase>
83+
</execution>
84+
</executions>
85+
</plugin>
86+
<plugin>
87+
<groupId>org.jacoco</groupId>
88+
<artifactId>jacoco-maven-plugin</artifactId>
89+
<executions>
90+
<execution>
91+
<id>aggregate-jacoco-reports</id>
92+
<phase>verify</phase>
93+
<goals>
94+
<goal>report-aggregate</goal>
95+
</goals>
96+
</execution>
97+
</executions>
98+
</plugin>
99+
<plugin>
100+
<groupId>com.societegenerale.commons</groupId>
101+
<artifactId>arch-unit-maven-plugin</artifactId>
102+
<configuration>
103+
<rules>
104+
<preConfiguredRules>
105+
<rule>com.societegenerale.commons.plugin.rules.NoJunitAssertRuleTest</rule>
106+
<rule>com.societegenerale.commons.plugin.rules.NoPowerMockRuleTest</rule>
107+
<rule>com.societegenerale.commons.plugin.rules.NoTestIgnoreRuleTest</rule>
108+
<rule>com.societegenerale.commons.plugin.rules.NoTestIgnoreWithoutCommentRuleTest
109+
</rule>
110+
</preConfiguredRules>
111+
</rules>
112+
</configuration>
113+
</plugin>
114+
</plugins>
115+
</build>
116+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package {{cookiecutter.package_name}}.cucumber;
2+
3+
import static io.cucumber.junit.platform.engine.Constants.*;
4+
5+
import org.junit.platform.suite.api.ConfigurationParameter;
6+
import org.junit.platform.suite.api.ConfigurationParameters;
7+
import org.junit.platform.suite.api.IncludeEngines;
8+
import org.junit.platform.suite.api.SelectClasspathResource;
9+
import org.junit.platform.suite.api.Suite;
10+
11+
@Suite
12+
@IncludeEngines("cucumber")
13+
@SelectClasspathResource("features/{{cookiecutter.domain}}.feature")
14+
@ConfigurationParameters({
15+
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "{{cookiecutter.package_name}}.cucumber"),
16+
@ConfigurationParameter(key = FILTER_TAGS_PROPERTY_NAME, value = "@{{cookiecutter.domain_capitalized}}"),
17+
@ConfigurationParameter(key = JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, value = "long"),
18+
@ConfigurationParameter(key = PLUGIN_PUBLISH_QUIET_PROPERTY_NAME, value = "true"),
19+
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "json:target/cucumber/cucumber.json")
20+
})
21+
public class RunCucumber{{cookiecutter.domain_capitalized}}Test {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package {{cookiecutter.package_name}}.cucumber;
2+
3+
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
4+
5+
import io.cucumber.spring.CucumberContextConfiguration;
6+
import org.springframework.boot.test.context.SpringBootTest;
7+
import org.springframework.test.context.ActiveProfiles;
8+
import {{cookiecutter.package_name}}.boot.{{cookiecutter.domain_capitalized}}Application;
9+
10+
@SpringBootTest(classes = {{cookiecutter.domain_capitalized}}Application.class, webEnvironment = RANDOM_PORT)
11+
@CucumberContextConfiguration
12+
@ActiveProfiles("test")
13+
public class SpringCucumberTestConfig {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package {{cookiecutter.package_name}}.cucumber;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.within;
5+
6+
import io.cucumber.datatable.DataTable;
7+
import io.cucumber.java8.En;
8+
import io.cucumber.java8.HookNoArgsBody;
9+
import java.time.LocalDateTime;
10+
import java.time.temporal.ChronoUnit;
11+
import java.util.List;
12+
import java.util.Map;
13+
import java.util.stream.Collectors;
14+
import org.springframework.boot.test.web.client.TestRestTemplate;
15+
import org.springframework.boot.test.web.server.LocalServerPort;
16+
import org.springframework.http.HttpStatus;
17+
import org.springframework.http.ResponseEntity;
18+
import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}};
19+
import {{cookiecutter.package_name}}.repository.dao.{{cookiecutter.domain_capitalized}}Dao;
20+
import {{cookiecutter.package_name}}.repository.entity.{{cookiecutter.domain_capitalized}}Entity;
21+
import {{cookiecutter.package_name}}.rest.generated.model.{{cookiecutter.domain_capitalized}}Info;
22+
import {{cookiecutter.package_name}}.rest.generated.model.ProblemDetail;
23+
24+
public class {{cookiecutter.domain_capitalized}}StepDef implements En {
25+
26+
private static final String LOCALHOST = "http://localhost:";
27+
private static final String API_URI = "/api/v1/{{cookiecutter.domain_plural}}";
28+
@LocalServerPort private int port;
29+
private ResponseEntity responseEntity;
30+
31+
public {{cookiecutter.domain_capitalized}}StepDef(TestRestTemplate restTemplate, {{cookiecutter.domain_capitalized}}Dao {{cookiecutter.domain}}Dao) {
32+
33+
DataTableType(
34+
(Map<String, String> row) ->
35+
{{cookiecutter.domain_capitalized}}.builder()
36+
.code(Long.parseLong(row.get("code")))
37+
.description(row.get("description"))
38+
.build());
39+
DataTableType(
40+
(Map<String, String> row) ->
41+
{{cookiecutter.domain_capitalized}}Entity.builder()
42+
.code(Long.parseLong(row.get("code")))
43+
.description(row.get("description"))
44+
.build());
45+
46+
Before((HookNoArgsBody) {{cookiecutter.domain}}Dao::deleteAll);
47+
After((HookNoArgsBody) {{cookiecutter.domain}}Dao::deleteAll);
48+
49+
Given(
50+
"the following {{cookiecutter.domain_plural}} exists in the library",
51+
(DataTable dataTable) -> {
52+
List<{{cookiecutter.domain_capitalized}}Entity> poems = dataTable.asList({{cookiecutter.domain_capitalized}}Entity.class);
53+
{{cookiecutter.domain}}Dao.saveAll(poems);
54+
});
55+
56+
When(
57+
"user requests for all {{cookiecutter.domain_plural}}",
58+
() -> {
59+
String url = LOCALHOST + port + API_URI;
60+
responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}Info.class);
61+
});
62+
63+
When(
64+
"user requests for {{cookiecutter.domain_plural}} by code {string}",
65+
(String code) -> {
66+
String url = LOCALHOST + port + API_URI + "/" + code;
67+
responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}.class);
68+
});
69+
70+
When(
71+
"user requests for {{cookiecutter.domain_plural}} by id {string} that does not exists",
72+
(String code) -> {
73+
String url = LOCALHOST + port + API_URI + "/" + code;
74+
responseEntity = restTemplate.getForEntity(url, ProblemDetail.class);
75+
});
76+
77+
Then(
78+
"the user gets an exception {string}",
79+
(String exception) -> {
80+
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
81+
var actualResponse = (ProblemDetail) responseEntity.getBody();
82+
var expectedProblemDetail =
83+
ProblemDetail.builder()
84+
.type("https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404")
85+
.status(HttpStatus.NOT_FOUND.value())
86+
.detail("{{cookiecutter.domain_capitalized}} with code 10000 does not exist")
87+
.instance("/api/v1/{{cookiecutter.domain_plural}}/10000")
88+
.title("{{cookiecutter.domain_capitalized}} not found")
89+
.build();
90+
assertThat(actualResponse).isNotNull();
91+
assertThat(actualResponse)
92+
.usingRecursiveComparison()
93+
.ignoringFields("timestamp")
94+
.isEqualTo(expectedProblemDetail);
95+
assertThat(actualResponse.getTimestamp())
96+
.isCloseTo(LocalDateTime.now(), within(100L, ChronoUnit.SECONDS));
97+
});
98+
99+
Then(
100+
"the user gets the following {{cookiecutter.domain_plural}}",
101+
(DataTable dataTable) -> {
102+
List<{{cookiecutter.domain_capitalized}}> expected{{cookiecutter.domain_plural_capitalized}} = dataTable.asList({{cookiecutter.domain_capitalized}}.class);
103+
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
104+
Object body = responseEntity.getBody();
105+
assertThat(body).isNotNull();
106+
if (body instanceof {{cookiecutter.domain_capitalized}}Info) {
107+
assertThat((({{cookiecutter.domain_capitalized}}Info) body).get{{cookiecutter.domain_plural_capitalized}}())
108+
.isNotEmpty()
109+
.extracting("description")
110+
.containsAll(
111+
expected{{cookiecutter.domain_plural_capitalized}}.stream()
112+
.map({{cookiecutter.domain_capitalized}}::getDescription)
113+
.collect(Collectors.toList()));
114+
} else if (body instanceof {{cookiecutter.domain_capitalized}}) {
115+
assertThat(body)
116+
.isNotNull()
117+
.extracting("description")
118+
.isEqualTo(expected{{cookiecutter.domain_plural_capitalized}}.get(0).getDescription());
119+
}
120+
});
121+
}
122+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
database:
2+
url: jdbc:h2:mem:testdb;MODE=PostgreSQL;
3+
driver-class-name: org.h2.Driver
4+
username: ''
5+
password: ''
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@{{cookiecutter.domain_capitalized}}
2+
Feature: User would like to get {{cookiecutter.domain_plural}}
3+
Background:
4+
Given the following {{cookiecutter.domain_plural}} exists in the library
5+
| code | description |
6+
| 1 | Twinkle twinkle little star |
7+
| 2 | Johnny Johnny Yes Papa |
8+
9+
Scenario: User should be able to get all {{cookiecutter.domain_plural}}
10+
When user requests for all {{cookiecutter.domain_plural}}
11+
Then the user gets the following {{cookiecutter.domain_plural}}
12+
| code | description |
13+
| 1 | Twinkle twinkle little star |
14+
| 2 | Johnny Johnny Yes Papa |
15+
16+
Scenario: User should be able to get {{cookiecutter.domain_plural}} by code
17+
When user requests for {{cookiecutter.domain_plural}} by code "1"
18+
Then the user gets the following {{cookiecutter.domain_plural}}
19+
| code | description |
20+
| 1 | Twinkle twinkle little star |
21+
22+
Scenario: User should get an appropriate NOT FOUND message while trying get {{cookiecutter.domain_plural}} by an invalid code
23+
When user requests for {{cookiecutter.domain_plural}} by id "10000" that does not exists
24+
Then the user gets an exception "{{cookiecutter.domain_capitalized}} with code 10000 does not exist"

{{cookiecutter.app_name}}/pom.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939
<module>jpa-adapter</module>
4040
<module>rest-adapter</module>
4141
<module>bootstrap</module>
42-
<!--
43-
<module>acceptance-test</module>-->
42+
<module>acceptance-test</module>
4443
</modules>
4544
<dependencyManagement>
4645
<dependencies>

0 commit comments

Comments
 (0)