Skip to content

Commit

Permalink
[Issue #70] Template for Rest API with Docker and WireMock
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Michalski committed Mar 30, 2020
1 parent d53915d commit 53a8fa2
Show file tree
Hide file tree
Showing 20 changed files with 1,075 additions and 0 deletions.
640 changes: 640 additions & 0 deletions sprimber-docs/src/main/docs/guides/rest-template.adoc

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions sprimber-docs/src/main/docs/guides/webui-template.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,7 @@ Congratulations!
First UI Selenium tests is now completed in Sprimber.
It will produce detailed report with screenshots and additional debug information for failed tests.
In our source code we changed Scenario to Scenario outline in feature file to support additional sub page object to show how easily additional models can be added.

For more information on Sprimber, please check additional templates:

* Building REST test automation with Sprimber
1 change: 1 addition & 0 deletions sprimber-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<modules>
<module>sprimber-echo-template</module>
<module>sprimber-rest-template</module>
<module>sprimber-webui-template</module>
</modules>

Expand Down
76 changes: 76 additions & 0 deletions sprimber-examples/sprimber-rest-template/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sprimber-examples</artifactId>
<groupId>com.griddynamics.qa</groupId>
<version>1.1.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sprimber-rest-template</artifactId>

<dependencies>
<dependency>
<groupId>com.griddynamics.qa</groupId>
<artifactId>sprimber-spring-boot-starter</artifactId>
<version>1.1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.2.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.10.0</version>
<configuration>
<resultsDirectory>${project.parent.parent.basedir}/allure-results</resultsDirectory>
<reportVersion>2.7.0</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.griddynamics.qa.sprimber.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RestTemplate {

public static void main(String[] args) throws Exception {
SpringApplication.exit(SpringApplication.run(RestTemplate.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.griddynamics.qa.sprimber.test.configuration;

public abstract class DataTableFields {
private DataTableFields() {
}

public static final String REQUEST_ID = "requestId";
public static final String COUNTRY = "country";
public static final String CITY = "city";
public static final String STATUS_CODE = "statusCode";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.griddynamics.qa.sprimber.test.configuration;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("rest")
@Data
public class RestProperties {
private String baseUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.griddynamics.qa.sprimber.test.configuration;

import com.griddynamics.qa.sprimber.scope.ScenarioScope;
import com.griddynamics.qa.sprimber.test.repository.WeatherClient;
import com.griddynamics.qa.sprimber.test.storage.WeatherStorage;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

@Configuration
@EnableConfigurationProperties({RestProperties.class})
@RequiredArgsConstructor
public class RestTemplateConfiguration {

private final RestProperties restProperties;

@Bean
public Retrofit weatherServiceRetrofit() {
return new Retrofit.Builder()
.baseUrl(restProperties.getBaseUrl())
.addConverterFactory(JacksonConverterFactory.create())
.build();
}

@Bean
public WeatherClient weatherClient(Retrofit weatherServiceRetrofit) {
return weatherServiceRetrofit.create(WeatherClient.class);
}

@Bean
@ScenarioScope
public WeatherStorage weatherStorage() {
return new WeatherStorage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.griddynamics.qa.sprimber.test.model;

import lombok.Data;

@Data
public class WeatherResponse {
private Double temperature;
private Long humidity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.griddynamics.qa.sprimber.test.repository;

import com.griddynamics.qa.sprimber.test.model.WeatherResponse;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface WeatherClient {
@GET("/currentWeather/{country}/{city}")
Call<WeatherResponse> getCurrentWeather(@Path("country") String country, @Path("city") String city);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.griddynamics.qa.sprimber.test.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.griddynamics.qa.sprimber.test.model.WeatherResponse;
import com.griddynamics.qa.sprimber.test.repository.WeatherClient;
import com.griddynamics.qa.sprimber.test.storage.WeatherStorage;
import io.qameta.allure.AllureLifecycle;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import retrofit2.Call;
import retrofit2.Response;

import java.io.IOException;
import java.util.Objects;

@Component
@RequiredArgsConstructor
@Slf4j
public class WeatherService {

private static final String EMPTY_RESPONSE_BODY = "Empty response body";

private final WeatherClient weatherClient;
private final WeatherStorage weatherStorage;
private final AllureLifecycle allureLifecycle;
private final ObjectMapper objectMapper;

public void getCurrentWeather(String requestId, String country, String city) {
log.debug("Calling weather service. RequestId: {}, Country: {}, City: {}", requestId, country, city);
Call<WeatherResponse> weatherResponseCall = weatherClient.getCurrentWeather(country, city);
try {
Response<WeatherResponse> weatherResponse = weatherResponseCall.execute();
weatherStorage.getWeatherResponseMap().put(requestId, weatherResponse);
allureLifecycle.addAttachment(
String.format("Weather service response for RequestId: %s, Country: %s, City: %s", requestId, country, city),
"application/json",
"json",
Objects.nonNull(weatherResponse.body()) ? objectMapper.writeValueAsBytes(weatherResponse.body()) : EMPTY_RESPONSE_BODY.getBytes());
} catch (IOException e) {
throw new IllegalArgumentException("Exception during call to current weather endpoint", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.griddynamics.qa.sprimber.test.service;

import com.griddynamics.qa.sprimber.test.model.WeatherResponse;
import com.griddynamics.qa.sprimber.test.storage.WeatherStorage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import retrofit2.Response;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;

@Component
@RequiredArgsConstructor
public class WeatherValidationService {

private final WeatherStorage weatherStorage;

public void isCallSuccessful(String requestId) {
Response<WeatherResponse> weatherResponse = weatherStorage.getWeatherResponseMap().get(requestId);
assertThat(weatherResponse)
.as(String.format("Weather response for requestId %s is null", requestId))
.isNotNull();
assertThat(weatherResponse.code())
.as("Weather response status code should be 200")
.isEqualTo(200);
assertThat(weatherResponse.body())
.as(String.format("Weather response body for requestId %s is null", requestId))
.isNotNull();
}

public void isCallFailedWithStatusCode(String requestId, Integer statusCode) {
Response<WeatherResponse> weatherResponse = weatherStorage.getWeatherResponseMap().get(requestId);
assertThat(weatherResponse)
.as(String.format("Weather response for requestId %s is null", requestId))
.isNotNull();
assertThat(weatherResponse.code())
.as(String.format("Weather response status code should be %d", statusCode))
.isEqualTo(statusCode);
}

public void areValuesPresentInCurrentWeatherResponse(String requestId) {
Response<WeatherResponse> weatherResponse = weatherStorage.getWeatherResponseMap().get(requestId);
assertThat(weatherResponse.body().getHumidity())
.as(String.format("Weather response for requestId %s humidity is not present", requestId))
.isNotNull();
assertThat(weatherResponse.body().getTemperature())
.as(String.format("Weather response for requestId %s temperature is not present", requestId))
.isNotNull();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.griddynamics.qa.sprimber.test.steps;

import com.griddynamics.qa.sprimber.discovery.Actions;
import com.griddynamics.qa.sprimber.test.service.WeatherService;
import com.griddynamics.qa.sprimber.test.service.WeatherValidationService;
import io.cucumber.datatable.DataTable;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import lombok.RequiredArgsConstructor;

import static com.griddynamics.qa.sprimber.test.configuration.DataTableFields.*;

@Actions
@RequiredArgsConstructor
public class WeatherSteps {

private final WeatherService weatherService;
private final WeatherValidationService weatherValidationService;

@Given("^Weather rest service is called with following values:$")
public void getCurrentWeather(DataTable dataTable) {
dataTable.asMaps()
.forEach(rowAsMap -> weatherService.getCurrentWeather(
rowAsMap.get(REQUEST_ID),
rowAsMap.get(COUNTRY),
rowAsMap.get(CITY)
));
}

@When("^following calls are successful:$")
public void getCurrentWeatherCallIsSuccessful(DataTable dataTable) {
dataTable.asMaps()
.forEach(rowAsMap -> weatherValidationService.isCallSuccessful(rowAsMap.get(REQUEST_ID)));
}

@When("^following calls are failed with status code:$")
public void getCurrentWeatherCallIsFailedWithStatusCode(DataTable dataTable) {
dataTable.asMaps()
.forEach(rowAsMap ->
weatherValidationService.isCallFailedWithStatusCode(
rowAsMap.get(REQUEST_ID),
Integer.valueOf(rowAsMap.get(STATUS_CODE)))
);
}

@Then("^temperature and humidity values are present for calls:$")
public void validateGetCurrentWeatherResponse(DataTable dataTable) {
dataTable.asMaps()
.forEach(rowAsMap -> weatherValidationService.areValuesPresentInCurrentWeatherResponse(rowAsMap.get(REQUEST_ID)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.griddynamics.qa.sprimber.test.storage;

import com.griddynamics.qa.sprimber.test.model.WeatherResponse;
import lombok.Data;
import retrofit2.Response;

import java.util.HashMap;
import java.util.Map;

@Data
public class WeatherStorage {
private final Map<String, Response<WeatherResponse>> weatherResponseMap = new HashMap<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
logging:
level:
com.griddynamics.qa.sprimber.lifecycle.TestCaseIlluminator: DEBUG
com.griddynamics.qa.sprimber.engine.executor: DEBUG
sprimber:
configuration:
featurePath: feature/**/*.feature
summary:
printer:
enable: true
tagFilters:
- "@smoke"
rest:
baseUrl: http://localhost:8089
Loading

0 comments on commit 53a8fa2

Please sign in to comment.