package net.petrikainulainen.spring.testmvc.todo.controller;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
import net.petrikainulainen.spring.testmvc.config.ExampleApplicationContext;
import net.petrikainulainen.spring.testmvc.todo.TestUtil;
import net.petrikainulainen.spring.testmvc.todo.dto.TodoDTO;
import net.petrikainulainen.spring.testmvc.todo.dto.TodoDTOBuilder;
import net.petrikainulainen.spring.testmvc.todo.model.Todo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import javax.annotation.Resource;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* This test uses the annotation based application context configuration.
* @author Petri Kainulainen
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ExampleApplicationContext.class})
//@ContextConfiguration(locations = {"classpath:exampleApplicationContext.xml"})
@WebAppConfiguration
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
@Resource
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
@ExpectedDatabase("toDoData.xml")
public void add_EmptyTodoEntry_ShouldReturnValidationErrorForTitle() throws Exception {
TodoDTO added = new TodoDTO();
mockMvc.perform(post("/api/todo")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(added))
)
.andExpect(status().isBadRequest())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.fieldErrors", hasSize(1)))
.andExpect(jsonPath("$.fieldErrors[0].path", is("title")))
.andExpect(jsonPath("$.fieldErrors[0].message", is("The title cannot be empty.")));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void add_TitleAndDescriptionAreTooLong_ShouldReturnValidationErrorsForTitleAndDescription() throws Exception {
String title = TestUtil.createStringWithLength(Todo.MAX_LENGTH_TITLE + 1);
String description = TestUtil.createStringWithLength(Todo.MAX_LENGTH_DESCRIPTION + 1);
TodoDTO added = new TodoDTOBuilder()
.description(description)
.title(title)
.build();
mockMvc.perform(post("/api/todo")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(added))
)
.andExpect(status().isBadRequest())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.fieldErrors", hasSize(2)))
.andExpect(jsonPath("$.fieldErrors[*].path", containsInAnyOrder("title", "description")))
.andExpect(jsonPath("$.fieldErrors[*].message", containsInAnyOrder(
"The maximum length of the description is 500 characters.",
"The maximum length of the title is 100 characters."
)));
}
@Test
@ExpectedDatabase(value="toDoData-add-expected.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
public void add_NewTodoEntry_ShouldAddTodoEntryAndReturnAddedEntry() throws Exception {
TodoDTO added = new TodoDTOBuilder()
.description("description")
.title("title")
.build();
mockMvc.perform(post("/api/todo")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(added))
)
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(3)))
.andExpect(jsonPath("$.description", is("description")))
.andExpect(jsonPath("$.title", is("title")));
}
@Test
@ExpectedDatabase("toDoData-delete-expected.xml")
public void deleteById_TodoEntryFound_ShouldDeleteTodoEntryAndReturnIt() throws Exception {
mockMvc.perform(delete("/api/todo/{id}", 1L))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.description", is("Lorem ipsum")))
.andExpect(jsonPath("$.title", is("Foo")));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void deleteById_TodoIsNotFound_ShouldReturnHttpStatusCode404() throws Exception {
mockMvc.perform(delete("/api/todo/{id}", 3L))
.andExpect(status().isNotFound());
}
@Test
@ExpectedDatabase("toDoData.xml")
public void findAll_TodosFound_ShouldReturnFoundTodoEntries() throws Exception {
mockMvc.perform(get("/api/todo"))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].id", is(1)))
.andExpect(jsonPath("$[0].description", is("Lorem ipsum")))
.andExpect(jsonPath("$[0].title", is("Foo")))
.andExpect(jsonPath("$[1].id", is(2)))
.andExpect(jsonPath("$[1].description", is("Lorem ipsum")))
.andExpect(jsonPath("$[1].title", is("Bar")));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void findById_TodoEntryFound_ShouldReturnFoundTodoEntry() throws Exception {
mockMvc.perform(get("/api/todo/{id}", 1L))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.description", is("Lorem ipsum")))
.andExpect(jsonPath("$.title", is("Foo")));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void findById_TodoEntryNotFound_ShouldReturnHttpStatusCode404() throws Exception {
mockMvc.perform(get("/api/todo/{id}", 3L))
.andExpect(status().isNotFound());
}
@Test
@ExpectedDatabase("toDoData.xml")
public void update_EmptyTodoEntry_ShouldReturnValidationErrorForTitle() throws Exception {
TodoDTO updated = new TodoDTOBuilder()
.id(1L)
.build();
mockMvc.perform(put("/api/todo/{id}", 1L)
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(updated))
)
.andExpect(status().isBadRequest())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.fieldErrors", hasSize(1)))
.andExpect(jsonPath("$.fieldErrors[0].path", is("title")))
.andExpect(jsonPath("$.fieldErrors[0].message", is("The title cannot be empty.")));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void update_TitleAndDescriptionAreTooLong_ShouldReturnValidationErrorsForTitleAndDescription() throws Exception {
String title = TestUtil.createStringWithLength(Todo.MAX_LENGTH_TITLE + 1);
String description = TestUtil.createStringWithLength(Todo.MAX_LENGTH_DESCRIPTION + 1);
TodoDTO updated = new TodoDTOBuilder()
.id(1L)
.description(description)
.title(title)
.build();
mockMvc.perform(put("/api/todo/{id}", 1L)
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(updated))
)
.andExpect(status().isBadRequest())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.fieldErrors", hasSize(2)))
.andExpect(jsonPath("$.fieldErrors[*].path", containsInAnyOrder("title", "description")))
.andExpect(jsonPath("$.fieldErrors[*].message", containsInAnyOrder(
"The maximum length of the description is 500 characters.",
"The maximum length of the title is 100 characters."
)));
}
@Test
@ExpectedDatabase("toDoData.xml")
public void update_TodoEntryNotFound_ShouldReturnHttpStatusCode404() throws Exception {
TodoDTO updated = new TodoDTOBuilder()
.id(3L)
.description("description")
.title("title")
.build();
mockMvc.perform(put("/api/todo/{id}", 3L)
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(updated))
)
.andExpect(status().isNotFound());
}
@Test
@ExpectedDatabase(value="toDoData-update-expected.xml", assertionMode = DatabaseAssertionMode.NON_STRICT)
public void update_TodoEntryFound_ShouldUpdateTodoEntryAndReturnIt() throws Exception {
TodoDTO updated = new TodoDTOBuilder()
.id(1L)
.description("description")
.title("title")
.build();
mockMvc.perform(put("/api/todo/{id}", 1L)
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(updated))
)
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.description", is("description")))
.andExpect(jsonPath("$.title", is("title")));
}
}