Setting session attributes for JUnits on Spring 3.2 - spring

I'm having trouble setting session attributes for a test. I am using MockMvc to test calls to a controller. The session model has a member attribute on it (representing the person who has logged in). The SessionModel object is added as a session attribute. I was expecting it to be populated in the ModelMap parameter to formBacking method below, but the ModelMap is always empty.
The controller code works fine when running through the webapp, but not in the JUnit. Any idea what I could be doing wrong?
Here is my JUnit Test
#Test
public void testUnitCreatePostSuccess() throws Exception {
UnitCreateModel expected = new UnitCreateModel();
expected.reset();
expected.getUnit().setName("Bob");
SessionModel sm = new SessionModel();
sm.setMember(getDefaultMember());
this.mockMvc.perform(
post("/units/create")
.param("unit.name", "Bob")
.sessionAttr(SessionModel.KEY, sm))
.andExpect(status().isOk())
.andExpect(model().attribute("unitCreateModel", expected))
.andExpect(view().name("tiles.content.unit.create"));
}
and here is the controller in question
#Controller
#SessionAttributes({ SessionModel.KEY, UnitCreateModel.KEY })
#RequestMapping("/units")
public class UnitCreateController extends ABaseController {
private static final String CREATE = "tiles.content.unit.create";
#Autowired
private IUnitMemberService unitMemberService;
#Autowired
private IUnitService unitService;
#ModelAttribute
public void formBacking(ModelMap model) {
SessionModel instanceSessionModel = new SessionModel();
instanceSessionModel.retrieveOrCreate(model);
UnitCreateModel instanceModel = new UnitCreateModel();
instanceModel.retrieveOrCreate(model);
}
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String onCreate(
#ModelAttribute(UnitCreateModel.KEY) UnitCreateModel model,
#ModelAttribute(SessionModel.KEY) SessionModel sessionModel) {
model.reset();
return CREATE;
}
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String onCreatePost(
#ModelAttribute(SessionModel.KEY) SessionModel sessionModel,
#Valid #ModelAttribute(UnitCreateModel.KEY) UnitCreateModel model,
BindingResult result) throws ServiceRecoverableException {
if (result.hasErrors()){
return CREATE;
}
long memberId = sessionModel.getMember().getId();
long unitId = unitService.create(model.getUnit());
unitMemberService.addMemberToUnit(memberId, unitId, true);
return CREATE;
}
}

For your test class add the #WebAppConfiguration annotation and autowire the following as well.(WebApplicationContext and MockHttpSession )
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration({ "classpath:springDispatcher-servlet.xml" })
public class MySessionControllerTest {
#Autowired WebApplicationContext wac;
#Autowired MockHttpSession session;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void testUnitCreatePostSuccess() throws Exception {
UnitCreateModel expected = new UnitCreateModel();
expected.reset();
expected.getUnit().setName("Bob");
SessionModel sm = new SessionModel();
sm.setMember(getDefaultMember());
session.setAttribute(SessionModel.KEY, sm);
this.mockMvc.perform(
post("/units/create")
.session(session)
.param("unit.name", "Bob")
.andExpect(status().isOk())
.andExpect(model().attribute("unitCreateModel", expected))
.andExpect(view().name("tiles.content.unit.create"));
}
}

Related

Writing a test to Spring boot REST API that retrieve data from a DB

I have a spring boot REST API with a GET method that returns data available in a DB. I am attempting to write an integration test to test this API method. I have configured the test to use the H2 database. I am trying to add some mock data to the database before the test is executed and see if the API retrieves that data. Following is the code I have written so far.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:application-test.properties")
public class MetaControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private ProvinceDAO provinceDAO;
#Transactional
#Before
public void addData () {
Province southern = getProvinceEntity("Southern", "දකුණ", "தென்");
provinceDAO.createEntity(southern);
System.out.println(provinceDAO.findAll(Province.class).size());
}
#Test
public void testGetProvinces() throws Exception {
MvcResult result = mvc.perform(get("/meta/provinces"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
}
However, when I run this code, I am getting an error saying "org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is java.lang.IllegalStateException: No transactional EntityManager available"
I have also attempted using #MockBean instead of #Autowired to bind the provinceDAO. Even though this prevents the error, it does not persist the entity in the database.
How should I write my testcase to test my method here?
Update:
application-test.properties
spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
Entity -> Province.java
#Entity
#Table(name = "w4a_province")
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "province_name")
private String name;
#Column(name = "province_name_si")
private String nameSi;
#Column(name = "province_name_ta")
private String nameTa;
.
.
}
GenericDAO.java
#Repository
public class GenericDAO<T> implements IGenericDAO<T> {
#PersistenceContext
private EntityManager em;
#Override
public Session getCurrentSession() {
return this.em.unwrap(Session.class);
}
#Override
public T findByPrimaryKey(Class<T> clazz, Object primaryKey) {
return getCurrentSession().find(clazz, primaryKey);
}
#Override
public List<T> findAll(Class<T> clazz) {
DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
return criteria.getExecutableCriteria(getCurrentSession()).list();
}
#Override
public T createEntity(T entity) {
getCurrentSession().save(entity);
return entity;
}
ProvinceDAOImpl.java
#Repository
public class ProvinceDAOImpl extends GenericDAO<Province> implements ProvinceDAO {
}
MetaController.java
#RestController
#PreAuthorize("permitAll()")
public class MetaController {
private final MetaService metaService;
#Autowired
public MetaController(MetaService metService) {
this.metaService = metService;
}
#GetMapping("/meta/provinces")
public ResponseEntity<List<ProvinceDTO>> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving list of provinces.");
}
List<ProvinceDTO> provinces = metaService.getProvinces();
return ResponseEntity.ok(provinces);
}
}
MetaServiceImpl.java
#Service
#Transactional
public class MetaServiceImpl implements MetaService {
private final ProvinceDAO provinceDAO;
#Autowired
public MetaServiceImpl(ProvinceDAO provnceDAO) {
this.provinceDAO = provnceDAO;
}
public List<ProvinceDTO> getProvinces() {
if (logger.isDebugEnabled()) {
logger.debug("Obtaining a list of provinces from database.");
}
List<Province> entities = provinceDAO.findAll(Province.class);
if (logger.isDebugEnabled()) {
logger.debug("Converting province entities to dtos.");
}
List<ProvinceDTO> dtos = new ArrayList<>();
for (int i = 0; i < entities.size(); i++) {
Province entity = entities.get(i);
if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.SINHALA_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameSi()));
} else if (LocaleContextHolder.getLocale().getLanguage().equals(
GlobalConstants.LanguageIdentifiers.TAMIL_LANGUAGE_TAG)) {
dtos.add(new ProvinceDTO(entity.getId(), entity.getNameTa()));
} else {
dtos.add(new ProvinceDTO(entity.getId(), entity.getName()));
}
}
return dtos;
}
}
I managed to feed the database with the required data by placing a SQL script data-h2.sql with insert queries at the test/resources folder. This prevented the requirement to use an EntityManager or a DAO.
Furthermore, I added the following property to the application-test.properties file.
spring.datasource.platform=h2
In Order to test Rest Api You can try functional test as well as integration test.
You can prepare your own response formate as required and check whether the same is returned or else you can also verify whether the data from db is fine or not.Plz check the below example
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = FactsMain.class)
#WebAppConfiguration
public abstract class BaseTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
In First test case i am forming the response format and trying to return the same and then validating the same.Here i don't need the db data so i have kept service as mock instead of auto wired.And used ObjectMapper for converting json to java and then java obj to json from base Test class.
public class PersonalDetailsControllerTest extends BaseTest {
#MockBean
private IPersonalService service;
private static final String URI = "/api/personalDetails";
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void testGet() throws Exception {
PersonalDetailsEntity entity = new PersonalDetailsEntity();
List<PersonalDetailsEntity> dataList = new ArrayList<PersonalDetailsEntity>();
FactsAdminResponse<PersonalDetailsEntity> dataResponse = new FactsAdminResponse<PersonalDetailsEntity>();
entity.setId(1);
entity.setName(“Anthony Holmes”);
entity.setAge(26);
entity.setCity(“Banglore”);
entity.setCountry(“India”);
dataList.add(entity);
dataResponse.setData(dataList);
Mockito.when(service.getBuildings()).thenReturn(dataList);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(URI)
.accept(MediaType.APPLICATION_JSON);
MvcResult mvcResult = mvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
String expectedJson = this.mapToJson(dataResponse);
String outputInJson = mvcResult.getResponse().getContentAsString();
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertEquals(expectedJson, outputInJson);
}
}
In below case we are getting the actual data in json format as we are doing rest api call and then just validating the status apart from status you can also cross check the data
public class PersonalDetailsControllerTest extends BaseTest {
private static final String URI = "/api/personalDetails";
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void getGet() throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(URL)
.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
//you got the content in string format now you can also validate the data
}

Spring boot testing error: java.lang.IllegalArgumentException: Page must not be null

I am trying to test the following controller:
#RepositoryRestController
#RequestMapping("movies")
public class MovieController {
private MovieService movieService;
private PagedResourcesAssembler<Movie> pagedAssembler;
private MovieResourceAssembler movieResourceAssembler;
#Autowired
public void setMovieService(MovieService movieService) {
this.movieService = movieService;
}
#Autowired
public void setPagedAssembler(PagedResourcesAssembler<Movie> pagedAssembler) {
this.pagedAssembler = pagedAssembler;
}
#Autowired
public void setMovieResourceAssembler(MovieResourceAssembler movieResourceAssembler) {
this.movieResourceAssembler = movieResourceAssembler;
}
// Return all movies with pagination
#GetMapping
public ResponseEntity<?> getAllMovies(Pageable pageable) {
Page<Movie> moviePage = this.movieService.getAllMovies(pageable);
// Remove some unnecessary fields
//this.movieService.removeUndesirableFieldsFromListing(moviePage);
return ResponseEntity.ok(this.pagedAssembler.toResource(moviePage, this.movieResourceAssembler));
}
}
and here's the test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MovieControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MovieService movieService;
#Test
public void getAllMovies_PageableGiven_ShouldReturnMoviesPage() throws Exception {
List<Movie> movieList = new ArrayList<>();
movieList.add(new Movie());
movieList.add(new Movie());
Page<Movie> moviePage = new PageImpl<>(movieList);
given(this.movieService.getAllMovies(PageRequest.of(0,2)))
.willReturn(moviePage);
this.mockMvc.perform(get("http://localhost:8080/api/movies?page=1"))
.andExpect(status().isOk());
}
}
i got the following error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Page must not be null!
You could use Spring's mockMvc object injecting it inside your test class:
#Autowired
private MockMvc mockMvc;
I have just created a test method using mockMvc.perform method sending a page request:
My controller code:
#GetMapping(produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public List<BaseResponse> listAllBase(
#PageableDefault(size = 50, page = 2) Pageable pageable) {
// logger.debug("paginación recibida :{}",pageable);
List<BaseResponse> findAllBases = baseService.findAllBases();
return findAllBases;
}
My test code:
mockMvc.perform(get("/base/?size=2&page=0")).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$", hasSize(2))) .andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].name", equalToIgnoringCase("margarita")))
See full Class code in my GitHub repo:
Controller:
https://github.com/cristianprofile/spring-boot-mvc-complete-example/blob/develop/spring-boot-mvc-rest/src/main/java/com/mylab/cromero/controller/HelloWorldController.java#L53
Test class method:
https://github.com/cristianprofile/spring-boot-mvc-complete-example/blob/develop/spring-boot-mvc-rest/src/test/java/com/mylab/cromero/controller/RestTestIT.java#L66
Feel free to use it in your project :)
By reading these two Stackoverflow threads ([1] and [2]) and also Spring documentation, it seems that you should use Page with repositories. Example:
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));
For your case, it's recommended to use PagedListHolder, instead. Example:
List<Movie> movieList = new ArrayList<>();
movieList.add(new Movie());
movieList.add(new Movie());
PagedListHolder<Movie> holder = new PagedListHolder<>(movieList);

Issue with Spring boot Controller with Mockito test case

I am completely new to Mockito and I have to write a test case for my REST Controller, but I am not sure where should I start. Any help would be really appreciated.I've updated my controller based on given suggestion.
Here's my controller:
#RestController
#RequestMapping("/api")
public class TestController {
#Autowired
TestService _testService;
#RequestMapping(value = "/getsearchDetailCourse", method = RequestMethod.GET)
public List<TestDto> getsearchDetailCourse(#RequestParam("courseName") String courseName,
#RequestParam("courseId") Long courseId) throws Exception {
return (List<TestDto>) _testService.searchDetailCourse(courseName, courseId);
}
}
My TestDto:
public class TestDto {
private String numberOfCourse;
private Long courseId;
public TestDto(){}
public TestDto(String numberOfCourse,Long courseId ){
super();
this.numberOfCourse = numberOfCourse;
this.courseId = courseId;
}
public String getNumberOfCourse() {
return numberOfCourse;
}
public void setNumberOfCourse(String numberOfCourse) {
this.numberOfCourse = numberOfCourse;
}
public Long getCourseId() {
return courseId;
}
public void setCourseId(Long courseId) {
this.courseId = courseId;
}
}
Here's my test:
#RunWith(SpringRunner.class)
#WebMvcTest(value = TestController.class, secure = false)
public class TestMethod {
#Autowired
private MockMvc mockMvc;
#MockBean
private TestService testService;
TestDto testDto = new testDto("Test",2744L);
#Test
public void retrieveDetailsForCourse() throws Exception {
Mockito.when(
testService.searchDetailCourse(Mockito.anyString(),
,Mockito.anyLong())).thenReturn(testDto);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
"/api/getsearchDetailCourse").accept(
MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println(result.getResponse());
String expected = "[{\"numberOfCourse\":\"Testing1\",\"courseId\":2744},{\"numberOfCourse\":\"Testing2\",\"courseId\":2744}]";
JSONAssert.assertEquals(expected, result.getResponse()
.getContentAsString(), false);
}
}
I want to test the controller, please help me correct the test case above.

Spring tests - mock returns null

I have a small issue with mocking methods . Where mock should return an predefined object, it returns null. here is test set up:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
#Autowired
WebApplicationContext webContext;
#MockBean
UserTransferService userTransferService;
#MockBean
UserService userService;
MockMvc mockMvc;
private User user = DummyObjects.getDummyUser();
private User modifiedUser = DummyObjects.getModifiedUser();
private UserTO userTO = DummyObjects.getDummyUserTO();
private UserTO modifiedUserTO = DummyObjects.getModifiedUserTO();
#Before
public void setUp() throws Exception {
List<User> users = new ArrayList<>();
users.add(modifiedUser);
users.add(user);
given(this.userTransferService.getTO(user)).willReturn(userTO);
given(this.userTransferService.getObject(userTO)).willReturn(user);
given(this.userTransferService.getTO(modifiedUser)).willReturn(modifiedUserTO);
given(this.userTransferService.getObject(modifiedUserTO)).willReturn(modifiedUser);
given(this.userService.findAll()).willReturn(users);
given(this.userService.save(user)).willReturn(user);
given(this.userService.removeById(1)).willReturn(true);
given(this.userService.getById(1)).willReturn(user);
given(this.userService.getById(2)).willReturn(null);
given(this.userService.modify(modifiedUser)).willReturn(modifiedUser);
given(this.userService.findByLogin(user.getLogin())).willReturn(user);
given(this.userService.findByLogin("AAA")).willReturn(null);
mockMvc = MockMvcBuilders
.webAppContextSetup(webContext)
.apply(springSecurity())
.build();
}
test itself:
#Test
public void shouldAddUser() throws Exception {
mockMvc.perform(post("/api/user")
.content(TestingUtility.asJsonString(userTO))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.with(csrf().asHeader()))
.andExpect(status().is(200))
.andExpect(content().json(TestingUtility.asJsonString(userTO)));
}
and Controller method:
#RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public UserTO modifyUser(#RequestBody UserTO userTO, UsernamePasswordAuthenticationToken principal) throws IllegalAccessException{
User user = userTransferService.getObject(userTO);
if (principal.getName().equals(userTO.getLogin()) || permissionService.hasPermission(principal,Permission.SU)) {
return userTransferService.getTO(userService.modify(user));
} else {
throw new IllegalAccessException("You are not allowed to modify user");
}
}
User is null, but UserTO is filled. So mocked method UserTransferService.getObject(userTO) is not working properly.

Spring MVC release 4.2.6 seems does not inject mock service into the controller when testing controller method

I really searched and followed the steps of creating a unit test class for spring MVC controller, however unit test is running with a green pass flag but the framework uses the original service class and it calls to the database. I mocked the class and used #InjectMocks together with MockitoAnnotations.initMocks(this). Still when the test runs, the controller uses original service object rather than the mocked object. I really appreciate if somebody can help me in this regards.
Here is UserManager(service class), UserRegisterController(controller), TestUserRegisterController (Test class) classes with a picture of the Eclipse package structure
Service :
#Service
public class UserManager {
protected Map<String, String> getAllCertificates() {
Map<String, String> allCertificates = new HashMap<String, String>();
//call to database
return allCertificates;
}
protected User getUser(int userId) {
//create session
User user = session.get(User.class, userId);
//close session
return user;
}
}
Controller :
#Controller
public class UserRegisterController {
#Autowired
private UserManager manager;
#InitBinder
public void initBinder(WebDataBinder binder) {
//do some work
}
#RequestMapping(value = "/user.html", method = RequestMethod.GET)
public ModelAndView getUser(#RequestParam(value="userId", defaultValue="-1") String userId) {
User user1;
user1 = this.manager.getUser(Integer.parseInt(userId));
if (user1 == null) {
user1 = new User();
}
ModelAndView view = new ModelAndView("User", "user1", user1);
view.addObject("allCertificatesMap", this.manager.getAllCertificates());
return view;
}
#ModelAttribute
public void setModelAttribute(Model model) {
model.addAttribute("PageHeader", "lable.pageHeader");
}
}
Test class :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("test-spring-dispatcher-servlet.xml")
#WebAppConfiguration
public class TestUserRegisterController {
#Mock
private UserManager userManager;
#InjectMocks
private UserRegisterController userRegisterController;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
// Process mock annotations
MockitoAnnotations.initMocks(this);
User user2 = new User();
user2.setUserId(10006);
user2.setUserName("Reza");
user2.setHobby("Quadcopter");
user2.setPhone("4032376295");
when(this.userManager.getUser(10006)).thenReturn(user2);
when(this.userManager.getAllCertificates()).thenReturn(new HashMap<String, String>());
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void getUser() {
try {
this.mockMvc.perform(get("/user.html").param("userId", "10006"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("/WEB-INF/jsp/User.jsp"))
.andExpect(MockMvcResultMatchers.view().name("User"))
.andExpect(model().attributeExists("allCertificatesMap"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Package hierarchy
Use #RunWith(MockitoJUnitRunner.class) to get the #InjectMocks and other annotations to work

Resources