Merge branch 'eugenp:master' into PR-6910

This commit is contained in:
parthiv39731
2023-10-11 10:34:08 +05:30
committed by GitHub
177 changed files with 3875 additions and 362 deletions
+6 -2
View File
@@ -60,7 +60,11 @@
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
@@ -273,7 +277,7 @@
<properties>
<java.version>19</java.version>
<mapstruct.version>1.5.2.Final</mapstruct.version>
<springdoc.version>2.0.0</springdoc.version>
<springdoc.version>2.2.0</springdoc.version>
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
<start-class>com.baeldung.sample.TodoApplication</start-class>
<mockserver.version>5.14.0</mockserver.version>
@@ -6,6 +6,8 @@ public class Article {
Integer id;
String title;
public Article() {}
public Article(Integer id, String title) {
this.id = id;
this.title = title;
@@ -19,6 +21,14 @@ public class Article {
return title;
}
public void setId(Integer id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -1,5 +1,6 @@
package com.baeldung.restclient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
@@ -13,13 +14,21 @@ public class ArticleController {
Map<Integer, Article> database = new HashMap<>();
@GetMapping
public Collection<Article> getArticles() {
return database.values();
public ResponseEntity<Collection<Article>> getArticles() {
Collection<Article> values = database.values();
if (values.isEmpty()) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(values);
}
@GetMapping("/{id}")
public Article getArticle(@PathVariable Integer id) {
return database.get(id);
public ResponseEntity<Article> getArticle(@PathVariable("id") Integer id) {
Article article = database.get(id);
if (article == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(article);
}
@PostMapping
@@ -28,7 +37,7 @@ public class ArticleController {
}
@PutMapping("/{id}")
public void updateArticle(@PathVariable Integer id, @RequestBody Article article) {
public void updateArticle(@PathVariable("id") Integer id, @RequestBody Article article) {
assert Objects.equals(id, article.getId());
database.remove(id);
database.put(id, article);
@@ -0,0 +1,6 @@
package com.baeldung.restclient;
public class ArticleNotFoundException extends RuntimeException {
public ArticleNotFoundException() {
}
}
@@ -0,0 +1,6 @@
package com.baeldung.restclient;
public class InvalidArticleResponseException extends RuntimeException {
public InvalidArticleResponseException() {
}
}
@@ -1,17 +1,23 @@
package com.baeldung.restclient;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClient;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@@ -22,7 +28,10 @@ public class RestClientIntegrationTest {
private String uriBase;
RestClient restClient = RestClient.create();
@BeforeAll
@Autowired
ObjectMapper objectMapper;
@BeforeEach
public void setup() {
uriBase = "http://localhost:" + port;
}
@@ -42,7 +51,7 @@ public class RestClientIntegrationTest {
.retrieve()
.body(String.class);
assertThat(articlesAsString).isEqualTo("[]");
assertThat(articlesAsString).isEqualTo("");
}
@Test
@@ -63,6 +72,48 @@ public class RestClientIntegrationTest {
assertThat(articles).isEqualTo(List.of(article));
}
@Test
void shouldPostAndGetArticlesWithExchange() {
assertThatThrownBy(this::getArticlesWithExchange).isInstanceOf(ArticleNotFoundException.class);
Article article = new Article(1, "How to use RestClient");
restClient.post()
.uri(uriBase + "/articles")
.contentType(MediaType.APPLICATION_JSON)
.body(article)
.retrieve()
.toBodilessEntity();
List<Article> articles = getArticlesWithExchange();
assertThat(articles).isEqualTo(List.of(article));
}
private List<Article> getArticlesWithExchange() {
return restClient.get()
.uri(uriBase + "/articles")
.exchange((request, response) -> {
if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(204))) {
throw new ArticleNotFoundException();
} else if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) {
return objectMapper.readValue(response.getBody(), new TypeReference<>() {});
} else {
throw new InvalidArticleResponseException();
}
});
}
@Test
void shouldPostAndGetArticlesWithErrorHandling() {
assertThatThrownBy(() -> {
restClient.get()
.uri(uriBase + "/articles/1234")
.retrieve()
.onStatus(status -> status.value() == 404, (request, response) -> { throw new ArticleNotFoundException(); })
.body(new ParameterizedTypeReference<>() {});
}).isInstanceOf(ArticleNotFoundException.class);
}
@Test
void shouldPostAndPutAndGetArticles() {
Article article = new Article(1, "How to use RestClient");
@@ -79,7 +130,7 @@ public class RestClientIntegrationTest {
.contentType(MediaType.APPLICATION_JSON)
.body(articleChanged)
.retrieve()
.toBodilessEntity();
.toBodilessEntity();
List<Article> articles = restClient.get()
.uri(uriBase + "/articles")
@@ -104,11 +155,12 @@ public class RestClientIntegrationTest {
.retrieve()
.toBodilessEntity();
List<Article> articles = restClient.get()
ResponseEntity<Void> entity = restClient.get()
.uri(uriBase + "/articles")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.body(new ParameterizedTypeReference<>() {});
.toBodilessEntity();
assertThat(articles).isEqualTo(List.of());
assertThat(entity.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204));
}
}
@@ -9,9 +9,10 @@
<description>This is simple boot application for Spring boot actuator test</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -39,16 +40,6 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -1,36 +1,56 @@
package com.baeldung.endpoints.enabling;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Configuration
public class SecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("password"))
.roles("USER")
.and()
.withUser("admin")
.password(encoder.encode("admin"))
.roles("USER", "ADMIN");
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest()
.hasRole("ADMIN"));
http.httpBasic();
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http.httpBasic(Customizer.withDefaults());
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests(authz -> {
authz.requestMatchers(mvc.pattern("/actuator/**"))
.hasRole("ADMIN")
.anyRequest()
.authenticated();
});
return http.build();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
@@ -1,9 +1,9 @@
package com.baeldung.endpoints.info;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "users")
@@ -15,7 +15,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.context.request.RequestContextListener;
import javax.servlet.ServletContext;
import jakarta.servlet.ServletContext;
@EnableScheduling
@ComponentScan("com.baeldung.metrics")
@@ -7,14 +7,14 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Component
public class MetricFilter implements Filter {
@@ -13,20 +13,20 @@ import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
public class EndpointEnablingIntegrationTest {
class EndpointEnablingIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "user", password = "password", roles = "USER")
public void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
void givenWrongAuthentication_whenCallingActuator_thenReturns401() throws Exception {
mockMvc.perform(get("/actuator"))
.andExpect(status().isForbidden());
}
@Test
@WithMockUser(username = "admin", password = "admin", roles = "ADMIN")
public void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
void givenProperAuthentication_whenCallingActuator_thenReturnsExpectedEndpoints() throws Exception {
mockMvc.perform(get("/actuator"))
.andExpect(jsonPath("$._links").exists())
.andExpect(jsonPath("$._links.beans").exists())
@@ -9,9 +9,10 @@
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -47,13 +48,12 @@
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>${spring-boot-cloud-connectors.version}</version>
</dependency>
</dependencies>
@@ -332,6 +332,7 @@
<servlet.version>4.0.0</servlet.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-cloud-gcp.version>1.0.0.RELEASE</spring-cloud-gcp.version>
<spring-boot-cloud-connectors.version>2.2.13.RELEASE</spring-boot-cloud-connectors.version>
</properties>
</project>
@@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@@ -12,12 +13,11 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.csrf()
.disable();
http.authorizeHttpRequests(expressionInterceptUrlRegistry ->
expressionInterceptUrlRegistry
.anyRequest()
.permitAll())
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}
@@ -1,10 +1,10 @@
package com.baeldung.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Book {
@@ -93,8 +93,8 @@
<properties>
<swagger-core-jakarta.version>2.2.11</swagger-core-jakarta.version>
<springwolf-kafka.version>0.12.1</springwolf-kafka.version>
<springwolf-ui.version>0.8.0</springwolf-ui.version>
<springwolf-kafka.version>0.14.0</springwolf-kafka.version>
<springwolf-ui.version>0.14.0</springwolf-ui.version>
<testcontainers-kafka.version>1.18.3</testcontainers-kafka.version>
</properties>
@@ -18,7 +18,9 @@
"operationId": "incoming-topic_publish",
"description": "More details for the incoming topic",
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
},
"message": {
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
@@ -32,7 +34,9 @@
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersIncomingPayloadDto"
},
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
}
}
}
@@ -42,7 +46,9 @@
"operationId": "outgoing-topic_subscribe",
"description": "More details for the outgoing topic",
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
},
"message": {
"schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
@@ -56,7 +62,9 @@
"$ref": "#/components/schemas/SpringKafkaDefaultHeadersOutgoingPayloadDto"
},
"bindings": {
"kafka": { }
"kafka": {
"bindingVersion": "0.4.0"
}
}
}
}
@@ -0,0 +1,2 @@
## Relevant Articles
- [Create a GraalVM Docker Image](https://www.baeldung.com/java-graalvm-docker-image)
@@ -9,9 +9,10 @@
<description>Module For Spring Boot MVC Web</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -4,10 +4,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class HelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -4,10 +4,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class SpringHelloWorldServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -2,7 +2,7 @@ package com.baeldung.common.error;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import javax.servlet.Servlet;
import jakarta.servlet.Servlet;
public class SpringHelloServletRegistrationBean extends ServletRegistrationBean {
@@ -4,9 +4,9 @@ import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
public class WebAppInitializer implements WebApplicationInitializer {
@@ -1,9 +1,9 @@
package com.baeldung.servlets.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@@ -1,10 +1,10 @@
package com.baeldung.servlets.servlets.javaee;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "AnnotationServlet", description = "Example Servlet Using Annotations", urlPatterns = { "/annotationservlet" })
@@ -1,9 +1,9 @@
package com.baeldung.servlets.servlets.javaee;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@@ -1,6 +1,6 @@
package com.baeldung.utils;
import javax.annotation.security.RolesAllowed;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -1,6 +1,6 @@
package com.baeldung.utils.controller;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -1,32 +1,34 @@
package com.baeldung.utils;
import com.baeldung.utils.controller.UtilsController;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.MockitoAnnotations.openMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class UtilsControllerIntegrationTest {
class UtilsControllerIntegrationTest {
@InjectMocks
private UtilsController utilsController;
private MockMvc mockMvc;
@Before
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
openMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController).build();
}
@Test
public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception {
String param = "testparam";
this.mockMvc.perform(post("/setParam").param("param", param).sessionAttr("parameter", param)).andExpect(status().isOk());
}
@@ -0,0 +1,6 @@
package com.baeldung.spytest;
public interface ExternalAlertService {
public boolean alert(Order order);
}
@@ -0,0 +1,18 @@
package com.baeldung.spytest;
import org.springframework.stereotype.Component;
@Component
public class NotificationService {
private ExternalAlertService externalAlertService;
public void notify(Order order) {
System.out.println(order);
}
public boolean raiseAlert(Order order) {
return externalAlertService.alert(order);
}
}
@@ -0,0 +1,49 @@
package com.baeldung.spytest;
import java.util.UUID;
public class Order {
private UUID id;
private String name;
private OrderType orderType;
private double orderQuantity;
private String address;
public Order(UUID id, String name, double orderQuantity, String address) {
this.id = id;
this.name = name;
this.orderQuantity = orderQuantity;
this.address = address;
}
public enum OrderType {
INDIVIDUAL, BULK;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public double getOrderQuantity() {
return orderQuantity;
}
public String getAddress() {
return address;
}
}
@@ -0,0 +1,19 @@
package com.baeldung.spytest;
import java.util.HashMap;
import java.util.UUID;
import org.springframework.stereotype.Component;
@Component
public class OrderRepository {
public static final HashMap<UUID, Order> orders = new HashMap<>();
public Order save(Order order) {
UUID orderId = UUID.randomUUID();
order.setId(orderId);
orders.put(UUID.randomUUID(), order);
return order;
}
}
@@ -0,0 +1,25 @@
package com.baeldung.spytest;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
public final OrderRepository orderRepository;
public final NotificationService notificationService;
public OrderService(OrderRepository orderRepository, NotificationService notificationService) {
this.orderRepository = orderRepository;
this.notificationService = notificationService;
}
public Order save(Order order) {
order = orderRepository.save(order);
notificationService.notify(order);
if (!notificationService.raiseAlert(order)) {
throw new RuntimeException("Alert not raised");
}
return order;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.spytest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpyTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpyTestApplication.class, args);
}
}
@@ -0,0 +1,35 @@
package com.baeldung.spytest;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
@SpringBootTest
class OrderServiceIntegrationTest {
@Autowired
OrderRepository orderRepository;
@SpyBean
NotificationService notificationService;
@SpyBean
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {
Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertNotNull(order.getId());
verify(notificationService).notify(any(Order.class));
}
}
@@ -0,0 +1,41 @@
package com.baeldung.spytest;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
class OrderServiceUnitTest {
@Spy
OrderRepository orderRepository;
@Spy
NotificationService notificationService;
@InjectMocks
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() {
UUID orderId = UUID.randomUUID();
Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(orderInput).when(orderRepository)
.save(any());
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertEquals(orderId, order.getId());
verify(notificationService).notify(any(Order.class));
}
}