1+ package com .baeldung .httpinterface ;
2+
3+ import org .apache .http .HttpStatus ;
4+ import org .junit .jupiter .api .AfterAll ;
5+ import org .junit .jupiter .api .BeforeAll ;
6+ import org .junit .jupiter .api .Test ;
7+ import org .mockserver .client .MockServerClient ;
8+ import org .mockserver .integration .ClientAndServer ;
9+ import org .mockserver .configuration .Configuration ;
10+
11+ import java .io .IOException ;
12+ import java .net .ServerSocket ;
13+ import java .util .List ;
14+
15+ import org .mockserver .model .HttpRequest ;
16+ import org .mockserver .model .MediaType ;
17+ import org .mockserver .verify .VerificationTimes ;
18+ import org .slf4j .event .Level ;
19+ import org .springframework .http .HttpMethod ;
20+ import org .springframework .http .HttpStatusCode ;
21+ import org .springframework .http .ResponseEntity ;
22+ import org .springframework .web .reactive .function .client .WebClient ;
23+ import org .springframework .web .reactive .function .client .WebClientResponseException ;
24+ import reactor .core .publisher .Mono ;
25+
26+ import static org .junit .jupiter .api .Assertions .assertThrows ;
27+ import static org .mockserver .integration .ClientAndServer .startClientAndServer ;
28+ import static org .mockserver .matchers .Times .exactly ;
29+ import static org .mockserver .model .HttpRequest .request ;
30+ import static org .mockserver .model .HttpResponse .response ;
31+ import static org .junit .jupiter .api .Assertions .assertEquals ;
32+
33+ class BooksServiceMockServerTest {
34+
35+ private static final String SERVER_ADDRESS = "localhost" ;
36+ private static final String PATH = "/books" ;
37+
38+ private static int serverPort ;
39+ private static ClientAndServer mockServer ;
40+ private static String serviceUrl ;
41+
42+ @ BeforeAll
43+ static void startServer () throws IOException {
44+ serverPort = getFreePort ();
45+ serviceUrl = "http://" + SERVER_ADDRESS + ":" + serverPort ;
46+
47+ Configuration config = Configuration .configuration ().logLevel (Level .WARN );
48+ mockServer = startClientAndServer (config , serverPort );
49+
50+ mockAllBooksRequest ();
51+ mockBookByIdRequest ();
52+ mockSaveBookRequest ();
53+ mockDeleteBookRequest ();
54+ }
55+
56+ @ AfterAll
57+ static void stopServer () {
58+ mockServer .stop ();
59+ }
60+
61+ @ Test
62+ void givenMockedGetResponse_whenGetBooksServiceMethodIsCalled_thenTwoBooksAreReturned () {
63+ BooksClient booksClient = new BooksClient (WebClient .builder ().baseUrl (serviceUrl ).build ());
64+ BooksService booksService = booksClient .getBooksService ();
65+
66+ List <Book > books = booksService .getBooks ();
67+ assertEquals (2 , books .size ());
68+
69+ mockServer .verify (
70+ HttpRequest .request ()
71+ .withMethod (HttpMethod .GET .name ())
72+ .withPath (PATH ),
73+ VerificationTimes .exactly (1 )
74+ );
75+ }
76+
77+ @ Test
78+ void givenMockedGetResponse_whenGetExistingBookServiceMethodIsCalled_thenCorrectBookIsReturned () {
79+ BooksClient booksClient = new BooksClient (WebClient .builder ().baseUrl (serviceUrl ).build ());
80+ BooksService booksService = booksClient .getBooksService ();
81+
82+ Book book = booksService .getBook (1 );
83+ assertEquals ("Book_1" , book .title ());
84+
85+ mockServer .verify (
86+ HttpRequest .request ()
87+ .withMethod (HttpMethod .GET .name ())
88+ .withPath (PATH + "/1" ),
89+ VerificationTimes .exactly (1 )
90+ );
91+ }
92+
93+ @ Test
94+ void givenMockedGetResponse_whenGetNonExistingBookServiceMethodIsCalled_thenCorrectBookIsReturned () {
95+ BooksClient booksClient = new BooksClient (WebClient .builder ().baseUrl (serviceUrl ).build ());
96+ BooksService booksService = booksClient .getBooksService ();
97+
98+ assertThrows (WebClientResponseException .class , () -> booksService .getBook (9 ));
99+ }
100+
101+ @ Test
102+ void givenCustomErrorHandlerIsSet_whenGetNonExistingBookServiceMethodIsCalled_thenCustomExceptionIsThrown () {
103+ BooksClient booksClient = new BooksClient (WebClient .builder ()
104+ .defaultStatusHandler (HttpStatusCode ::isError , resp ->
105+ Mono .just (new MyServiceException ("Custom exception" )))
106+ .baseUrl (serviceUrl )
107+ .build ());
108+
109+ BooksService booksService = booksClient .getBooksService ();
110+ assertThrows (MyServiceException .class , () -> booksService .getBook (9 ));
111+ }
112+
113+ @ Test
114+ void givenMockedPostResponse_whenSaveBookServiceMethodIsCalled_thenCorrectBookIsReturned () {
115+ BooksClient booksClient = new BooksClient (WebClient .builder ().baseUrl (serviceUrl ).build ());
116+ BooksService booksService = booksClient .getBooksService ();
117+
118+ Book book = booksService .saveBook (new Book (3 , "Book_3" , "Author_3" , 2000 ));
119+ assertEquals ("Book_3" , book .title ());
120+
121+ mockServer .verify (
122+ HttpRequest .request ()
123+ .withMethod (HttpMethod .POST .name ())
124+ .withPath (PATH ),
125+ VerificationTimes .exactly (1 )
126+ );
127+ }
128+
129+ @ Test
130+ void givenMockedDeleteResponse_whenDeleteBookServiceMethodIsCalled_thenCorrectCodeIsReturned () {
131+ BooksClient booksClient = new BooksClient (WebClient .builder ().baseUrl (serviceUrl ).build ());
132+ BooksService booksService = booksClient .getBooksService ();
133+
134+ ResponseEntity <Void > response = booksService .deleteBook (3 );
135+ assertEquals (HttpStatusCode .valueOf (200 ), response .getStatusCode ());
136+
137+ mockServer .verify (
138+ HttpRequest .request ()
139+ .withMethod (HttpMethod .DELETE .name ())
140+ .withPath (PATH + "/3" ),
141+ VerificationTimes .exactly (1 )
142+ );
143+ }
144+
145+ private static int getFreePort () throws IOException {
146+ try (ServerSocket serverSocket = new ServerSocket (0 )) {
147+ return serverSocket .getLocalPort ();
148+ }
149+ }
150+
151+ private static void mockAllBooksRequest () {
152+ new MockServerClient (SERVER_ADDRESS , serverPort )
153+ .when (
154+ request ()
155+ .withPath (PATH )
156+ .withMethod (HttpMethod .GET .name ()),
157+ exactly (1 )
158+ )
159+ .respond (
160+ response ()
161+ .withStatusCode (HttpStatus .SC_OK )
162+ .withContentType (MediaType .APPLICATION_JSON )
163+ .withBody ("[{\" id\" :1,\" title\" :\" Book_1\" ,\" author\" :\" Author_1\" ,\" year\" :1998},{\" id\" :2,\" title\" :\" Book_2\" ,\" author\" :\" Author_2\" ,\" year\" :1999}]" )
164+ );
165+ }
166+
167+ private static void mockBookByIdRequest () {
168+ new MockServerClient (SERVER_ADDRESS , serverPort )
169+ .when (
170+ request ()
171+ .withPath (PATH + "/1" )
172+ .withMethod (HttpMethod .GET .name ()),
173+ exactly (1 )
174+ )
175+ .respond (
176+ response ()
177+ .withStatusCode (HttpStatus .SC_OK )
178+ .withContentType (MediaType .APPLICATION_JSON )
179+ .withBody ("{\" id\" :1,\" title\" :\" Book_1\" ,\" author\" :\" Author_1\" ,\" year\" :1998}" )
180+ );
181+ }
182+
183+ private static void mockSaveBookRequest () {
184+ new MockServerClient (SERVER_ADDRESS , serverPort )
185+ .when (
186+ request ()
187+ .withPath (PATH )
188+ .withMethod (HttpMethod .POST .name ())
189+ .withContentType (MediaType .APPLICATION_JSON )
190+ .withBody ("{\" id\" :3,\" title\" :\" Book_3\" ,\" author\" :\" Author_3\" ,\" year\" :2000}" ),
191+ exactly (1 )
192+ )
193+ .respond (
194+ response ()
195+ .withStatusCode (HttpStatus .SC_OK )
196+ .withContentType (MediaType .APPLICATION_JSON )
197+ .withBody ("{\" id\" :3,\" title\" :\" Book_3\" ,\" author\" :\" Author_3\" ,\" year\" :2000}" )
198+ );
199+ }
200+
201+ private static void mockDeleteBookRequest () {
202+ new MockServerClient (SERVER_ADDRESS , serverPort )
203+ .when (
204+ request ()
205+ .withPath (PATH + "/3" )
206+ .withMethod (HttpMethod .DELETE .name ()),
207+ exactly (1 )
208+ )
209+ .respond (
210+ response ()
211+ .withStatusCode (HttpStatus .SC_OK )
212+ );
213+ }
214+
215+ }
0 commit comments