1
package by.andd3dfx.templateapp.controllers;
3
import by.andd3dfx.templateapp.IntegrationTestInitializer;
4
import by.andd3dfx.templateapp.SpringBootTemplateApplication;
5
import by.andd3dfx.templateapp.dto.ArticleDto;
6
import by.andd3dfx.templateapp.dto.ArticleUpdateDto;
7
import org.junit.jupiter.api.BeforeEach;
8
import org.junit.jupiter.api.Test;
9
import org.springframework.beans.factory.annotation.Autowired;
10
import org.springframework.boot.test.context.SpringBootTest;
11
import org.springframework.http.MediaType;
12
import org.springframework.http.converter.HttpMessageConverter;
13
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
14
import org.springframework.mock.http.MockHttpOutputMessage;
15
import org.springframework.test.context.ContextConfiguration;
16
import org.springframework.test.context.web.WebAppConfiguration;
17
import org.springframework.test.web.servlet.MockMvc;
18
import org.springframework.web.context.WebApplicationContext;
20
import java.io.IOException;
21
import java.time.LocalDateTime;
23
import static org.hamcrest.CoreMatchers.containsString;
24
import static org.hamcrest.CoreMatchers.is;
25
import static org.hamcrest.CoreMatchers.notNullValue;
26
import static org.hamcrest.MatcherAssert.assertThat;
27
import static org.hamcrest.Matchers.hasSize;
28
import static org.springframework.test.util.AssertionErrors.assertNotNull;
29
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
30
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
31
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
32
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
33
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
34
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
35
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
37
@ContextConfiguration(initializers = IntegrationTestInitializer.class)
40
class ArticleControllerTest {
42
private final MediaType CONTENT_TYPE = new MediaType(
43
MediaType.APPLICATION_JSON.getType(),
44
MediaType.APPLICATION_JSON.getSubtype());
45
private MockMvc mockMvc;
46
private HttpMessageConverter httpMessageConverter;
49
private WebApplicationContext webApplicationContext;
52
void setConverter(MappingJackson2HttpMessageConverter converter) {
53
httpMessageConverter = converter;
54
assertNotNull("the JSON message converter must not be null", httpMessageConverter);
59
mockMvc = webAppContextSetup(webApplicationContext)
64
public void createArticle() throws Exception {
65
ArticleDto articleDto = new ArticleDto();
66
articleDto.setTitle("Some tittle value");
67
articleDto.setSummary("Some summary value");
68
articleDto.setText("Some text");
69
articleDto.setAuthor("Some author");
71
mockMvc.perform(post("/api/v1/articles")
72
.contentType(CONTENT_TYPE)
73
.content(json(articleDto))
75
.andExpect(status().isCreated())
76
.andExpect(jsonPath("$.id", notNullValue()))
77
.andExpect(jsonPath("$.title", is(articleDto.getTitle())))
78
.andExpect(jsonPath("$.summary", is(articleDto.getSummary())))
79
.andExpect(jsonPath("$.text", is(articleDto.getText())))
80
.andExpect(jsonPath("$.author", is(articleDto.getAuthor())))
81
.andExpect(jsonPath("$.dateCreated", notNullValue()))
82
.andExpect(jsonPath("$.dateUpdated", notNullValue()));
86
public void createArticleWithIdPopulated() throws Exception {
87
ArticleDto articleDto = new ArticleDto();
88
articleDto.setId(123L);
89
articleDto.setTitle("Some tittle value");
90
articleDto.setSummary("Some summary value");
91
articleDto.setText("Some text");
92
articleDto.setAuthor("Some author");
94
final String message = mockMvc.perform(post("/api/v1/articles")
95
.contentType(CONTENT_TYPE)
96
.content(json(articleDto))
98
.andExpect(status().isBadRequest())
99
.andReturn().getResolvedException().getMessage();
100
assertThat(message, containsString("Article id shouldn't be present"));
104
public void createArticleWithoutTitle() throws Exception {
105
ArticleDto articleDto = new ArticleDto();
106
articleDto.setSummary("Some summary value");
107
articleDto.setText("Some text");
108
articleDto.setAuthor("Some author");
110
final String message = mockMvc.perform(post("/api/v1/articles")
111
.contentType(CONTENT_TYPE)
112
.content(json(articleDto))
114
.andExpect(status().isBadRequest())
115
.andReturn().getResolvedException().getMessage();
116
assertThat(message, containsString("Title should be populated"));
120
public void createArticleWithEmptyTitle() throws Exception {
121
ArticleDto articleDto = new ArticleDto();
122
articleDto.setTitle("");
123
articleDto.setSummary("Some summary value");
124
articleDto.setText("Some text");
125
articleDto.setAuthor("Some author");
127
final String message = mockMvc.perform(post("/api/v1/articles")
128
.contentType(CONTENT_TYPE)
129
.content(json(articleDto))
131
.andExpect(status().isBadRequest())
132
.andReturn().getResolvedException().getMessage();
133
assertThat(message, containsString("Title length must be between 1 and 100"));
137
public void createArticleWithTooLongTitle() throws Exception {
138
ArticleDto articleDto = new ArticleDto();
139
articleDto.setTitle(createStringWithLength(101));
140
articleDto.setSummary("Some summary value");
141
articleDto.setText("Some text");
142
articleDto.setAuthor("Some author");
144
String message = mockMvc.perform(post("/api/v1/articles")
145
.contentType(CONTENT_TYPE)
146
.content(json(articleDto))
148
.andExpect(status().isBadRequest())
149
.andReturn().getResolvedException().getMessage();
150
assertThat(message, containsString("Title length must be between 1 and 100"));
154
public void createArticleWithTooLongSummary() throws Exception {
155
ArticleDto articleDto = new ArticleDto();
156
articleDto.setTitle("Some title");
157
articleDto.setSummary(createStringWithLength(260));
158
articleDto.setText("Some text");
159
articleDto.setAuthor("Some author");
161
String message = mockMvc.perform(post("/api/v1/articles")
162
.contentType(CONTENT_TYPE)
163
.content(json(articleDto))
165
.andExpect(status().isBadRequest())
166
.andReturn().getResolvedException().getMessage();
167
assertThat(message, containsString("Summary length shouldn't be greater than 255"));
171
public void createArticleWithoutText() throws Exception {
172
ArticleDto articleDto = new ArticleDto();
173
articleDto.setTitle("Some title");
174
articleDto.setSummary("Some summary value");
175
articleDto.setAuthor("Some author");
177
String message = mockMvc.perform(post("/api/v1/articles")
178
.contentType(CONTENT_TYPE)
179
.content(json(articleDto))
181
.andExpect(status().isBadRequest())
182
.andReturn().getResolvedException().getMessage();
183
assertThat(message, containsString("Text should be populated"));
187
public void createArticleWithEmptyText() throws Exception {
188
ArticleDto articleDto = new ArticleDto();
189
articleDto.setTitle("Some title");
190
articleDto.setSummary("Some summary value");
191
articleDto.setText("");
192
articleDto.setAuthor("Some author");
194
String message = mockMvc.perform(post("/api/v1/articles")
195
.contentType(CONTENT_TYPE)
196
.content(json(articleDto))
198
.andExpect(status().isBadRequest())
199
.andReturn().getResolvedException().getMessage();
200
assertThat(message, containsString("Text length should be 1 at least"));
204
public void createArticleWithoutAuthor() throws Exception {
205
ArticleDto articleDto = new ArticleDto();
206
articleDto.setTitle("Some title");
207
articleDto.setSummary("Some summary value");
208
articleDto.setText("Some text");
210
String message = mockMvc.perform(post("/api/v1/articles")
211
.contentType(CONTENT_TYPE)
212
.content(json(articleDto))
214
.andExpect(status().isBadRequest())
215
.andReturn().getResolvedException().getMessage();
216
assertThat(message, containsString("Author should be populated"));
220
public void createArticleWithDateCreatedPopulated() throws Exception {
221
ArticleDto articleDto = new ArticleDto();
222
articleDto.setTitle("Some tittle value");
223
articleDto.setSummary("Some summary value");
224
articleDto.setText("Some text");
225
articleDto.setAuthor("Some author");
226
articleDto.setDateCreated(LocalDateTime.now());
228
String message = mockMvc.perform(post("/api/v1/articles")
229
.contentType(CONTENT_TYPE)
230
.content(json(articleDto))
232
.andExpect(status().isBadRequest())
233
.andReturn().getResolvedException().getMessage();
234
assertThat(message, containsString("DateCreated shouldn't be populated"));
238
public void createArticleWithDateUpdatedPopulated() throws Exception {
239
ArticleDto articleDto = new ArticleDto();
240
articleDto.setTitle("Some tittle value");
241
articleDto.setSummary("Some summary value");
242
articleDto.setText("Some text");
243
articleDto.setAuthor("Some author");
244
articleDto.setDateUpdated(LocalDateTime.now());
246
String message = mockMvc.perform(post("/api/v1/articles")
247
.contentType(CONTENT_TYPE)
248
.content(json(articleDto))
250
.andExpect(status().isBadRequest())
251
.andReturn().getResolvedException().getMessage();
252
assertThat(message, containsString("DateUpdated shouldn't be populated"));
256
public void deleteArticle() throws Exception {
257
mockMvc.perform(delete("/api/v1/articles/1")
258
.contentType(CONTENT_TYPE)
260
.andExpect(status().isNoContent());
264
public void deleteAbsentArticle() throws Exception {
265
mockMvc.perform(delete("/api/v1/articles/9999")
266
.contentType(CONTENT_TYPE))
267
.andExpect(status().isNotFound());
271
public void readArticle() throws Exception {
272
mockMvc.perform(get("/api/v1/articles/1")
273
.contentType(CONTENT_TYPE)
275
.andExpect(status().isOk())
276
.andExpect(jsonPath("$.id", is(1)));
280
public void readAbsentArticle() throws Exception {
281
mockMvc.perform(get("/api/v1/articles/345")
282
.contentType(CONTENT_TYPE))
283
.andExpect(status().isNotFound());
287
public void readArticles() throws Exception {
288
mockMvc.perform(get("/api/v1/articles")
289
.contentType(CONTENT_TYPE)
291
.andExpect(status().isOk())
292
.andExpect(jsonPath("$.content", hasSize(10)))
293
.andExpect(jsonPath("$.number", is(0)))
294
.andExpect(jsonPath("$.size", is(50)))
295
.andExpect(jsonPath("$.totalPages", is(1)))
296
.andExpect(jsonPath("$.totalElements", is(10)));
300
public void readArticlesWithPageSizeLimit() throws Exception {
301
mockMvc.perform(get("/api/v1/articles")
303
.contentType(CONTENT_TYPE)
305
.andExpect(status().isOk())
306
.andExpect(jsonPath("$.content", hasSize(5)))
307
.andExpect(jsonPath("$.number", is(0)))
308
.andExpect(jsonPath("$.size", is(5)))
309
.andExpect(jsonPath("$.totalPages", is(2)))
310
.andExpect(jsonPath("$.totalElements", is(9)))
315
public void updateArticleTitle() throws Exception {
316
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
317
articleUpdateDto.setTitle("Some tittle value");
319
mockMvc.perform(patch("/api/v1/articles/2")
320
.contentType(CONTENT_TYPE)
321
.content(json(articleUpdateDto))
323
.andExpect(status().isOk());
327
public void updateArticleSummary() throws Exception {
328
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
329
articleUpdateDto.setSummary("Some summary value");
331
mockMvc.perform(patch("/api/v1/articles/2")
332
.contentType(CONTENT_TYPE)
333
.content(json(articleUpdateDto))
335
.andExpect(status().isOk());
339
public void updateArticleText() throws Exception {
340
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
341
articleUpdateDto.setText("Some text value");
343
mockMvc.perform(patch("/api/v1/articles/2")
344
.contentType(CONTENT_TYPE)
345
.content(json(articleUpdateDto))
347
.andExpect(status().isOk());
351
public void updateArticleMultipleFields() throws Exception {
352
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
353
articleUpdateDto.setSummary("Some summary value");
354
articleUpdateDto.setText("Some text value");
356
String message = mockMvc.perform(patch("/api/v1/articles/2")
357
.contentType(CONTENT_TYPE)
358
.content(json(articleUpdateDto))
360
.andExpect(status().isBadRequest())
361
.andReturn().getResolvedException().getMessage();
362
assertThat(message, containsString("Only one field should be modified at once"));
366
public void updateAbsentArticle() throws Exception {
367
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
368
articleUpdateDto.setTitle("q");
370
mockMvc.perform(patch("/api/v1/articles/123")
371
.contentType(CONTENT_TYPE)
372
.content(json(articleUpdateDto)))
373
.andExpect(status().isNotFound());
377
public void updateArticleWithEmptyTitle() throws Exception {
378
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
379
articleUpdateDto.setTitle("");
381
String message = mockMvc.perform(patch("/api/v1/articles/2")
382
.contentType(CONTENT_TYPE)
383
.content(json(articleUpdateDto))
385
.andExpect(status().isBadRequest())
386
.andReturn().getResolvedException().getMessage();
387
assertThat(message, containsString("Title length must be between 1 and 100"));
391
public void updateArticleWithTooLongTitle() throws Exception {
392
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
393
articleUpdateDto.setTitle(createStringWithLength(101));
395
String message = mockMvc.perform(patch("/api/v1/articles/2")
396
.contentType(CONTENT_TYPE)
397
.content(json(articleUpdateDto))
399
.andExpect(status().isBadRequest())
400
.andReturn().getResolvedException().getMessage();
401
assertThat(message, containsString("Title length must be between 1 and 100"));
405
public void updateArticleWithTooLongSummary() throws Exception {
406
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
407
articleUpdateDto.setSummary(createStringWithLength(260));
409
String message = mockMvc.perform(patch("/api/v1/articles/2")
410
.contentType(CONTENT_TYPE)
411
.content(json(articleUpdateDto))
413
.andExpect(status().isBadRequest())
414
.andReturn().getResolvedException().getMessage();
415
assertThat(message, containsString("Summary length shouldn't be greater than 255"));
419
public void updateArticleWithEmptyText() throws Exception {
420
ArticleUpdateDto articleUpdateDto = new ArticleUpdateDto();
421
articleUpdateDto.setText("");
423
String message = mockMvc.perform(patch("/api/v1/articles/2")
424
.contentType(CONTENT_TYPE)
425
.content(json(articleUpdateDto))
427
.andExpect(status().isBadRequest())
428
.andReturn().getResolvedException().getMessage();
429
assertThat(message, containsString("Text length should be 1 at least"));
432
private String json(Object o) throws IOException {
433
MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
434
httpMessageConverter.write(o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
435
return mockHttpOutputMessage.getBodyAsString();
438
private String createStringWithLength(int length) {
439
StringBuilder builder = new StringBuilder();
440
for (int index = 0; index < length; index++) {
443
return builder.toString();