initData = new HashMap<>();
- initData.put("ISBN-TEST-1", new BookData("ISBN-TEST-1", "Book 1", "Book 1 Author"));
- initData.put("ISBN-TEST-2", new BookData("ISBN-TEST-2", "Book 2", "Book 2 Author"));
- initData.put("ISBN-TEST-3", new BookData("ISBN-TEST-3", "Book 3", "Book 3 Author"));
+ initData.put("ISBN-1", new BookData("ISBN-1", "Book 1", "Book 1 Author"));
+ initData.put("ISBN-2", new BookData("ISBN-2", "Book 2", "Book 2 Author"));
+ initData.put("ISBN-3", new BookData("ISBN-3", "Book 3", "Book 3 Author"));
return initData;
}
}
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/add-book.jsp b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/add-book.jsp
index 3b815dfafb..8195743da8 100644
--- a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/add-book.jsp
+++ b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/add-book.jsp
@@ -2,22 +2,20 @@
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
-
- Add Book
-
-
+
+ Add Book
+
+
+
+ Successfully added Book with ISBN: ${savedBook.isbn}
+
-
- Successfully added Book with ISBN: ${savedBook.isbn}
-
-
-
-
- ISBN:
- Book Name:
- Author Name:
-
-
-
-
+
+
+ ISBN:
+ Book Name:
+ Author Name:
+
+
+
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/error-book.jsp b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/error-book.jsp
index c04756462d..6db90ca5c7 100644
--- a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/error-book.jsp
+++ b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/error-book.jsp
@@ -7,12 +7,12 @@
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
-
- Error
-
-
-Reference: ${ref}
-Error Message: ${message}
-Object: ${object}
-
+
+ Error
+
+
+ Reference: ${ref}
+ Error Message: ${message}
+ Object: ${object}
+
diff --git a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/view-books.jsp b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/view-books.jsp
index 46bfbbac99..4a8e00a69b 100644
--- a/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/view-books.jsp
+++ b/spring-web-modules/spring-boot-jsp/src/main/webapp/WEB-INF/jsp/view-books.jsp
@@ -1,30 +1,28 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
-
- View Books
-
- " rel="stylesheet" type="text/css">
-
-
-
-
-
-
- ISBN |
- Name |
- Author |
-
-
-
-
+
+ View Books
+ " rel="stylesheet" type="text/css">
+
+
+
+
- ${book.isbn} |
- ${book.name} |
- ${book.author} |
+ ISBN |
+ Name |
+ Author |
-
-
-
-
+
+
+
+
+ ${book.isbn} |
+ ${book.name} |
+ ${book.author} |
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerIntegrationTest.java b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerIntegrationTest.java
new file mode 100644
index 0000000000..1847cbf545
--- /dev/null
+++ b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerIntegrationTest.java
@@ -0,0 +1,93 @@
+package com.baeldung.boot.jsp.controller;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasProperty;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+
+import com.baeldung.boot.jsp.repository.BookRepository;
+import com.baeldung.boot.jsp.repository.impl.InMemoryBookRepository;
+import com.baeldung.boot.jsp.repository.model.BookData;
+
+@ExtendWith(SpringExtension.class)
+@WebAppConfiguration
+@ContextConfiguration
+@AutoConfigureMockMvc
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class BookControllerIntegrationTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private BookRepository bookRepository;
+
+ @Test
+ @Order(1)
+ public void whenAddBook_thenBookSaved() throws Exception {
+ MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
+ .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ .param("isbn", "isbn1")
+ .param("name", "name1")
+ .param("author", "author1");
+ mockMvc.perform(addBookRequest)
+ .andReturn();
+
+ Optional storedBookOpt = bookRepository.findById("isbn1");
+ assertTrue(storedBookOpt.isPresent());
+ assertEquals("name1", storedBookOpt.get()
+ .getName());
+ assertEquals("author1", storedBookOpt.get()
+ .getAuthor());
+ }
+
+ @Test
+ @Order(2)
+ public void givenAlreadyExistingBook_whenAddBook_thenShowErrorPage() throws Exception {
+ MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
+ .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ .param("isbn", "isbn1")
+ .param("name", "name1")
+ .param("author", "author1");
+ ResultActions addBookResult = mockMvc.perform(addBookRequest);
+
+ addBookResult.andExpect(view().name("error-book"))
+ .andExpect(model().attribute("ref", "isbn1"))
+ .andExpect(model().attribute("object", hasProperty("isbn", equalTo("isbn1"))))
+ .andExpect(model().attribute("message", "Cannot add an already existing book"));
+ }
+
+ @Configuration
+ @ComponentScan("com.baeldung.boot.jsp")
+ static class ContextConfiguration {
+
+ @Bean
+ public BookRepository provideBookRepository() {
+ return new InMemoryBookRepository(Collections.emptyMap());
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerUnitTest.java b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerUnitTest.java
new file mode 100644
index 0000000000..af1d3d4956
--- /dev/null
+++ b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/controller/BookControllerUnitTest.java
@@ -0,0 +1,76 @@
+package com.baeldung.boot.jsp.controller;
+
+import static org.hamcrest.Matchers.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.AdditionalAnswers;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+
+import com.baeldung.boot.jsp.dto.Book;
+import com.baeldung.boot.jsp.service.BookService;
+
+@WebMvcTest(BookController.class)
+class BookControllerUnitTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private BookService bookService;
+
+ @Test
+ public void whenViewBooks_thenReturnBooksView() throws Exception {
+ when(bookService.getBooks()).thenReturn(existingBooks());
+ ResultActions viewBooksResult = mockMvc.perform(get("/book/viewBooks"));
+
+ viewBooksResult.andExpect(view().name("view-books"))
+ .andExpect(model().attribute("books", hasSize(3)));
+ }
+
+ @Test
+ public void whenAddBookView_thenReturnAddBooksView() throws Exception {
+ ResultActions addBookViewResult = mockMvc.perform(get("/book/addBook"));
+
+ addBookViewResult.andExpect(view().name("add-book"))
+ .andExpect(model().attribute("book", isA(Book.class)));
+ }
+
+ @Test
+ public void whenAddBookPost_thenRedirectToAddBookView() throws Exception {
+ when(bookService.addBook(any(Book.class))).thenAnswer(AdditionalAnswers.returnsFirstArg());
+ MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
+ .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ .param("isbn", "isbn1")
+ .param("name", "name1")
+ .param("author", "author1");
+ ResultActions addBookResult = mockMvc.perform(addBookRequest);
+
+ addBookResult.andExpect(status().is3xxRedirection())
+ .andExpect(redirectedUrl("/book/addBook"))
+ .andExpect(flash().attribute("savedBook", hasProperty("isbn", equalTo("isbn1"))))
+ .andExpect(flash().attribute("addBookSuccess", true));
+ }
+
+ private static Collection existingBooks() {
+ List books = new ArrayList<>();
+ books.add(new Book("isbn1", "name1", "author1"));
+ books.add(new Book("isbn2", "name2", "author2"));
+ books.add(new Book("isbn3", "name3", "author3"));
+ return books;
+ }
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/repository/impl/InMemoryBookRepositoryUnitTest.java b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/repository/impl/InMemoryBookRepositoryUnitTest.java
new file mode 100644
index 0000000000..83f0c19e26
--- /dev/null
+++ b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/repository/impl/InMemoryBookRepositoryUnitTest.java
@@ -0,0 +1,62 @@
+package com.baeldung.boot.jsp.repository.impl;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.boot.jsp.repository.BookRepository;
+import com.baeldung.boot.jsp.repository.model.BookData;
+
+public class InMemoryBookRepositoryUnitTest {
+
+ @Test
+ public void givenEmtpyData_whenFindAll_thenReturnEmptyCollection() {
+ BookRepository bookRepository = new InMemoryBookRepository(Collections.emptyMap());
+ Collection storedBooks = bookRepository.findAll();
+
+ assertEquals(0, storedBooks.size());
+ }
+
+ @Test
+ public void givenInitialData_whenFindAll_thenReturnInitialData() {
+ BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
+ Collection storedBooks = bookRepository.findAll();
+
+ assertEquals(3, storedBooks.size());
+ }
+
+ @Test
+ public void givenInitialData_whenFindUnavailableIsbn_thenReturnEmpty() {
+ BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
+ Optional storedBookOpt = bookRepository.findById("isbn4");
+
+ assertFalse(storedBookOpt.isPresent());
+ }
+
+ @Test
+ public void givenInitialData_whenFindAvailableIsbn_thenReturnItem() {
+ BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
+ Optional storedBookOpt = bookRepository.findById("isbn1");
+
+ assertTrue(storedBookOpt.isPresent());
+ }
+
+ @Test
+ public void givenAddedIsbn_whenFindAvailableIsbn_thenReturnItem() {
+ BookRepository bookRepository = new InMemoryBookRepository(Collections.emptyMap());
+ bookRepository.add(new BookData("isbn4", "name4", "author4"));
+ Optional storedBookOpt = bookRepository.findById("isbn4");
+
+ assertTrue(storedBookOpt.isPresent());
+ }
+
+ private static Map initialBookData() {
+ Map initData = new HashMap<>();
+ initData.put("isbn1", new BookData("isbn1", "name1", "author1"));
+ initData.put("isbn2", new BookData("isbn2", "name2", "author2"));
+ initData.put("isbn3", new BookData("isbn3", "name3", "author3"));
+ return initData;
+ }
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/BookServiceIntegrationTest.java b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/BookServiceIntegrationTest.java
new file mode 100644
index 0000000000..4223f3f970
--- /dev/null
+++ b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/BookServiceIntegrationTest.java
@@ -0,0 +1,84 @@
+package com.baeldung.boot.jsp.service;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import com.baeldung.boot.jsp.dto.Book;
+import com.baeldung.boot.jsp.exception.DuplicateBookException;
+import com.baeldung.boot.jsp.repository.BookRepository;
+import com.baeldung.boot.jsp.repository.impl.InMemoryBookRepository;
+import com.baeldung.boot.jsp.repository.model.BookData;
+
+@ExtendWith(SpringExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
+public class BookServiceIntegrationTest {
+
+ @Autowired
+ private BookService bookService;
+
+ @Test
+ @Order(1)
+ public void givenNoAddedBooks_whenGetAllBooks_thenReturnInitialBooks() {
+ Collection storedBooks = bookService.getBooks();
+
+ assertEquals(3, storedBooks.size());
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-1"))));
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-2"))));
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-3"))));
+ }
+
+ @Test
+ @Order(2)
+ public void givenBookNotAlreadyExists_whenAddBook_thenReturnSuccessfully() {
+ Book bookToBeAdded = new Book("ISBN-ADD-TEST-4", "Added Book 4", "Added Book 4 Author");
+ Book storedBook = bookService.addBook(bookToBeAdded);
+
+ assertEquals(bookToBeAdded.getIsbn(), storedBook.getIsbn());
+ }
+
+ @Test
+ @Order(3)
+ public void givenBookAlreadyExists_whenAddBook_thenDuplicateBookException() {
+ Book bookToBeAdded = new Book("ISBN-ADD-TEST-4", "Updated Book 4", "Updated Book 4 Author");
+
+ assertThrows(DuplicateBookException.class, () -> bookService.addBook(bookToBeAdded));
+ }
+
+ @Configuration
+ @ComponentScan("com.baeldung.boot.jsp")
+ static class ContextConfiguration {
+
+ @Bean
+ public BookRepository provideBookRepository() {
+ return new InMemoryBookRepository(initialBookData());
+ }
+
+ private static Map initialBookData() {
+ Map initData = new HashMap<>();
+ initData.put("ISBN-TEST-1", new BookData("ISBN-TEST-1", "Book 1", "Book 1 Author"));
+ initData.put("ISBN-TEST-2", new BookData("ISBN-TEST-2", "Book 2", "Book 2 Author"));
+ initData.put("ISBN-TEST-3", new BookData("ISBN-TEST-3", "Book 3", "Book 3 Author"));
+ return initData;
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/impl/BookServiceImplUnitTest.java b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/impl/BookServiceImplUnitTest.java
new file mode 100644
index 0000000000..defbf71fd9
--- /dev/null
+++ b/spring-web-modules/spring-boot-jsp/src/test/java/com/baeldung/boot/jsp/service/impl/BookServiceImplUnitTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.boot.jsp.service.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.baeldung.boot.jsp.dto.Book;
+import com.baeldung.boot.jsp.exception.DuplicateBookException;
+import com.baeldung.boot.jsp.repository.BookRepository;
+import com.baeldung.boot.jsp.repository.model.BookData;
+import com.baeldung.boot.jsp.service.BookService;
+
+@ExtendWith(MockitoExtension.class)
+public class BookServiceImplUnitTest {
+
+ @Mock
+ private BookRepository bookRepository;
+
+ @Test
+ public void whenGetBooks_thenAllBooksReturned() {
+ when(bookRepository.findAll()).thenReturn(existingBooks());
+ BookService bookService = new BookServiceImpl(bookRepository);
+
+ Collection storedBooks = bookService.getBooks();
+ assertEquals(3, storedBooks.size());
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn1"))));
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn2"))));
+ assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn3"))));
+ }
+
+ @Test
+ public void whenAddBook_thenAddSuccessful() {
+ when(bookRepository.findById(anyString())).thenReturn(Optional.empty());
+ when(bookRepository.add(any(BookData.class))).thenAnswer(AdditionalAnswers.returnsFirstArg());
+ BookService bookService = new BookServiceImpl(bookRepository);
+ Book book = bookService.addBook(new Book("isbn1", "name1", "author1"));
+
+ assertEquals("isbn1", book.getIsbn());
+ assertEquals("name1", book.getName());
+ assertEquals("author1", book.getAuthor());
+ }
+
+ @Test
+ public void givenBookAlreadyExist_whenAddBook_thenDuplicateBookException() {
+ BookData existingBook = new BookData("isbn1", "name1", "author1");
+ when(bookRepository.findById("isbn1")).thenReturn(Optional.of(existingBook));
+ BookService bookService = new BookServiceImpl(bookRepository);
+ Book bookToBeAdded = new Book("isbn1", "name1", "author1");
+
+ assertThrows(DuplicateBookException.class, () -> bookService.addBook(bookToBeAdded));
+ }
+
+ private static Collection existingBooks() {
+ List books = new ArrayList<>();
+ books.add(new BookData("isbn1", "name1", "author1"));
+ books.add(new BookData("isbn2", "name2", "author2"));
+ books.add(new BookData("isbn3", "name3", "author3"));
+ return books;
+ }
+}
\ No newline at end of file