mvc controller test with session attribute - spring-mvc

I'm trying to test a method with this signature:
#Autowired
HttpSession http_Session;
#RequestMapping(method=RequestMethod.GET, value="/search/findByName")
public #ResponseBody List<Map> search(#RequestParam(value="name", required=true) String name){
Integer user_id = http_Session.getAttribute("userinfo");
}
userinfo is a class which contains informations about the user and set in session scope when the user logged in.but when I try the test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {
"classpath:/META-INF/applicationContext.xml"})
public class userControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
#Test
public void userTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/search/findByName").param("name", "bob"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());
}
The problem is the userinfo class attribute is set in another method so when i try to access it in this method i got a NullPointerException , and with Autowiring the httpSession i got a new Session for each method i have to test.
What should i do with the session attribute, my method doesn't accept a session parameter , and for each test it create a WebApplicationContext with a new session.

Try this :
HashMap<String, Object> sessionattr = new HashMap<String, Object>();
sessionattr.put("userinfo", "XXXXXXXX");
mockMvc.perform(MockMvcRequestBuilders.get("/search/findByName").sessionAttrs(sessionattr).param("name", "bob"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());

You could also share a session across different requests:
import static org.springframework.test.web.servlet.setup.SharedHttpSessionConfigurer.sharedHttpSession;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.webApplicationContext)
.apply(sharedHttpSession()) // use this session across requests
.build();
}
note: this session will be shared among requests performed against the same MockMvc instance only.

Related

No mapping found for HTTP request with URI [/api/transactions] in DispatcherServlet with name ''

I thought this is a standard configuration. But I get a 404 back. Where else should I configure Spring Boot ?
#RestController
#RequestMapping("/api")
public class TransactionStatisticsController {
public static final Logger logger = LoggerFactory.getLogger(TransactionStatisticsController.class);
#RequestMapping(value = "/transactions",
method = RequestMethod.POST)
public ResponseEntity sendTransaction(#RequestBody Transaction request) {
logger.info( request.toString());
return new ResponseEntity(HttpStatus.OK);
}
}
This is my test.
#JsonTest
#SpringBootTest(classes = Application.class)
#AutoConfigureMockMvc
#RunWith(SpringRunner.class)
public class TransactionStatisticsRestTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private JacksonTester<Transaction> json;
private static Transaction transaction;
#BeforeClass
public static void createTransaction(){
BigDecimal amount = new BigDecimal(12.3343);
transaction = new Transaction(amount.toString(),
"2010-10-02T12:23:23Z");
}
#Test
public void getTransactionStatus() throws Exception {
final String transactionJson = json.write(transaction).getJson();
mockMvc
.perform(post("/api/transactions")
.content(transactionJson)
.contentType(APPLICATION_JSON_UTF8))
.andExpect(status().isOk());
}
public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsBytes(transaction);
}
}
Request being made is
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/transactions
Parameters = {}
Headers = {Content-Type=[application/json;charset=UTF-8]}
Body = {"amount":"12.3343000000000007077005648170597851276397705078125","timestamp":"2010-10-02T12:23:23Z[UTC]"}
Session Attrs = {}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 404
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Update : I added a component scan pointing to a base package. I don't see that error now. Please see the comments where there is an answer.
As in the comment section ,there was only requirement was to bind a component scan base package location .
#Component scan -->Configures component scanning directives for use with #Configuration classes. Provides support parallel with Spring XML's element.
Either basePackageClasses() or basePackages() (or its alias value()) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
Please share your project folder architecture. It might be possible that your controller package is out of the main class package. That's why it is showing 404.
This code :
#RestController
#RequestMapping("/api")
public class TransactionStatisticsController {
public static final Logger logger = LoggerFactory.getLogger(TransactionStatisticsController.class);
#RequestMapping(value = "/transactions",
method = RequestMethod.POST)
public ResponseEntity sendTransaction(#RequestBody Transaction request) {
logger.info( request.toString());
return new ResponseEntity(HttpStatus.OK);
}
}
This should be into your main package where
#SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}
this main class resides.
I hope, this will help.
Seems using #JsonTest does not even allow to load Application Context, results mapping is not loaded and its throw 404 so #JsonTest is not a replacement for #SpringBootTest, it is a way to easily test json serialization/de-serialization.
As per documentation:
you can use the #JsonTest annotation. #JsonTest auto-configures the
available supported JSON mapper, which can be one of the following
libraries:
Jackson ObjectMapper, any #JsonComponent beans and any Jackson Modules
Gson
Jsonb
If by using Gson and removing #JsonTest your test run fine..(add Gson Dependency in pom)
#SpringBootTest
#AutoConfigureMockMvc
#RunWith(SpringRunner.class)
public class DemoKj01ApplicationTests {
#Autowired
private MockMvc mockMvc;
private static Transaction transaction;
#BeforeClass
public static void createTransaction(){
BigDecimal amount = new BigDecimal(12.3343);
transaction = new Transaction(amount.toString(),
"2010-10-02T12:23:23Z");
}
#Test
public void getTransactionStatus() throws Exception {
//final String transactionJson = json.write(transaction).getJson();
Gson gson = new Gson();
String jsonRequest = gson.toJson(transaction);
mockMvc
.perform(post("/api/transactions")
.content(jsonRequest)
.contentType(APPLICATION_JSON_UTF8))
.andExpect(status().isOk());
}
It is beacause of the trailing slas in #RequestMapping(value = "/transactions/", method = RequestMethod.POST)
Remove it and it will be ok : value = "/transactions/" => value = "/transactions"

Unable to Mock the Database call handled by Spring JPA framework while writing test Case for Controller Class

Spring MVC converts the id from path to corresponding object by making call to JpaRepository's findById method. For example see getVersionTree() method.
public class Controller {
#NonNull
private final MyService service;
#NonNull
private final MyAssembler assembler;
#GetMapping(path = VERSION_TREE_MAPPING, produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public HttpEntity<?> getVersionTree(#PathVariable("id") MappingDocument mappingDocument, Pageable pageable, PagedResourcesAssembler<VersionNode> pagedResourcesAssembler) {
Page<VersionNode> versionNodes = service.getVersionTreeFor(mappingDocument, pageable);
return new ResponseEntity<>(pagedResources, HttpStatus.OK);
}
While testing, SpringMVC throws " Failed to convert value of type 'java.lang.String' to required type 'com.rbc.dna.dtl.mappingdocument.MappingDocument'". I am mocking jpaRepository.findById() method. Test Code is as follows:
#Autowired
private WebApplicationContext webApplicationContext;
#MockBean
private MyRepository repository;
#Mock
MyController controller;
#MockBean
private MyServiceImpl serviceImpl;
#Test
public void testMethod() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(SecurityMockMvcConfigurers.springSecurity()).build();
MappingDocument mappingDocumentl=MappingDocument.builder().id(17L).build();
Mockito.when(repository.findById(17L)).thenReturn(Optional.of(mappingDocumentl));
Mockito.when(serviceImpl.getVersionTreeFor(mappingDocument,pageable)).thenReturn(pagedResponse);
mockMvc.perform(MockMvcRequestBuilders.get("/abc/17/def").param("page","0").param("size","20").contentType(MediaTypes.HAL_JSON_UTF8_VALUE)
.with(authentication(getOauthTestAuthentication()))
.sessionAttr("scopedTarget.oauth2ClientContext", getOauth2ClientContext()))
.andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
Your rest Controller take #PathVariable("id") MappingDocument mappingDocument as variable in your path, but in mockMvc.perform you are passing a simple String/Number or something that doesn't bind with MappingDocument.
Try to replace
public HttpEntity<?> getVersionTree(#PathVariable("id") MappingDocument mappingDocument...
with
public HttpEntity<?> getVersionTree(#PathVariable("id") Long idMappingDocument, ...
If you want to keep your object in #PathVariable you need to change
#GetMapping(path = VERSION_TREE_MAPPING)
To parse an object as PathVariable you need to have path that represent property of your object.
For example if you have
class Person {
String name;
String address;
//getters and setters
}
and you need to define a controller as follow:
#GetMapping(path = "/person/{name}/{address}", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public HttpEntity<?> getVersionTree(Person person) {
Where {name} and {address} must bind Person properties

Spring mvc unit test controller inject dao object using mockito

When using mockito to unit test Spring mvc controller, how to inject dao layer object. It's always giving null pointer exception with #Spy annotation when making use of SpringJUnit4ClassRunner class.
Sample code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:**/evivecare-application-context-test.xml" })
#WithMockUser(username = "admin", roles={"ADMIN"})
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class ControllerTest {
private MockMvc mockMvc;
#Mock
private SessionFactory sessionFactory;
#Mock
private Session session;
#InjectMocks
private FilterController filterController = new FilterController();
#Spy
private FilterService filterService= new FilterServiceImpl();
#Autowired
private FilterDAO filterDAO;
#Mock
private OperatorService userService;
#Mock
private EviveSpeechFilterService eviveSpeechFilterService;
private TestContextManager testContextManager;
#Before
public void setup() throws Exception {
// Process mock annotations
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(filterController).build();
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
filterDAO= new FilterDAOImpl(sessionFactory);
Mockito.doReturn(session).when(sessionFactory).getCurrentSession();
}
#Test
public void testController200() throws Exception{
Mockito.when(filterService.renameList("123","sdfgh")).thenReturn(false);
Mockito.when(filterDAO.renameList("123","sdfgh")).thenReturn(false);
this.mockMvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post("/renameList")
.sessionAttr("filterService", filterService)
.sessionAttr("filterDAO", filterDAO)
.param("listId", "1234567")
.param("alternateName", "LIst Name"))
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.status().isOk());
}
}
In this test case, the filterService in turn calls filterDAO, which is always returning null pointer exception.
So, what can I do to resolve this issue?
FilterService is not a managed bean, you probably need to inject the dao in the constructor since it won't be autowired inside filterService.
Please refer to this question on SO for more info: Support for autowiring in a class not instantiated by spring (3)

How to write a mockito test case for ResourceAssembler with in Spring Hateos?

I am trying to write a unit test for the below Assembler but i keep getting Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?. I wanted to know how i can mock out the resource creation?
#Component
public class LoginResourceAssembler extends ResourceAssemblerSupport<User, ResourceSupport> {
public LoginResourceAssembler() {
super(User.class, ResourceSupport.class);
}
#Override
public ResourceSupport toResource(User user) {
ResourceSupport resource = new ResourceSupport();
final String id = user.getId();
resource.add(linkTo(MyAccountsController.class).slash(id).slash("accounts").withRel("accounts"));
return resource;
}
}
Instead of changing from a plain unit test to a IMO integration test (given dependency of the spring framework) you could do something like:
#RunWith(MockitoJUnitRunner.class)
public class LoginResourceAssemblerTest {
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
}
#Test
public void testToResource() {
//...
}
}
I was seeing the error Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler because my test class was annotated with #RunWith(MockitoJUnitRunner.class) and this was not injecting the controller.
To fix this error, i annotated my test case with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
A working test case in my case
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class LoginResourceAssemblerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testToResource() {
User user = new User();
user.setId("1234");
ResourceSupport resource = loginResourceAssembler.toResource(user);
assertEquals(1,resource.getLinks().size());
assertEquals("accounts",resource.getLinks().get(0).getRel());
assertTrue(resource.getLinks().get(0).getHref().contains("accounts"));
}
}

Spring MVC test case

Am new to Spring MVC, i have written web servise using spring MVC and resteasy. My controller is working fine, now need to write testcase but i tried writtig but i never succed am also getting problem in autowiring.
#Controller
#Path("/searchapi")
public class SearchAPIController implements ISearchAPIController {
#Autowired
private ISearchAPIService srchapiservice;
#GET
#Path("/{domain}/{group}/search")
#Produces({"application/xml", "application/json"})
public Collections getSolrData(
#PathParam("domain") final String domain,
#PathParam("group") final String group,
#Context final UriInfo uriinfo) throws Exception {
System.out.println("LANDED IN get****************");
return srchapiservice.getData(domain, group, uriinfo);
}
}
can anyone give me sample code for Test case in spring mvc.
"Spring-MVC" Test case could seem like this using mock objects, for example we want to test my MyControllerToBeTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/spring.xml")
public class MyControllerTest {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyControllerToBeTested controller;
private AnnotationMethodHandlerAdapter adapter;
#Autowired
private ApplicationContext applicationContext;
#Before
public void setUp() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
response.setOutputStreamAccessAllowed(true);
controller = new MyControllerToBeTested();
adapter = new AnnotationMethodHandlerAdapter();
}
#Test
public void findRelatedVideosTest() throws Exception {
request.setRequestURI("/mypath");
request.setMethod("GET");
request.addParameter("myParam", "myValue");
adapter.handle(request, response, controller);
System.out.println(response.getContentAsString());
}
}
but i don't have any experience with REST resource testing, in your case RestEasy.
If you want to test the full service inside the container you can have a look at the REST Assured framework for Java. It makes it very easy to test and validate HTTP/REST-based services.

Resources