0

We have a Spring Rest Controller which accepts a User object with (Authenticated annotation) and a couple of other parameters. Can you please let us know how to pass this user object in JUnit test method. We are trying to call as below in the test method, but getting below exception stack trace.

Test invocation:

mockMvc.perform(get("/test1/test2/test3/test4")
    .with(SecurityMockMvcRequestPostProcessors.user(new UsrHelpr().create()))
    .accept(MediaType.APPLICATION_JSON)
    .param("name", "testting"))
    .andExpect(status().isOk()).andReturn();

Stack trace:

java.lang.AssertionError: Status expected:<200> but was:<400>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
    <<The line number is the code I have pasted above in the test class >>
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
glytching
  • 44,936
  • 9
  • 114
  • 120
sat1219
  • 25
  • 1
  • 5
  • Hi, I had re-ran with correct parameters to test method: as below: mockMvc.perform(get("/provision/warehouse/user/request") .with(SecurityMockMvcRequestPostProcessors.user(new UserHelper().create())).accept(MediaType.APPLICATION_JSON).param("status", "test")).andExpect(status().isOk()).andReturn(); – sat1219 Sep 07 '17 at 14:50
  • The above way ran successfully, but when we checked in debug mode, the user object is gettting passed as null. please let us know how to pass user object in test method. – sat1219 Sep 07 '17 at 14:58
  • I suggest you add those comments in the question so that they can be easily read. – alayor Sep 07 '17 at 15:41

1 Answers1

0

In your case, simply pass the user object as param values to the mock mvc request like below :

package com.example.stackoverflowsecurityissue;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TestController {

    @RequestMapping(value = "/request", method = RequestMethod.GET)
    public ResponseEntity getMyRequests(MyUser user, @RequestParam(value = "status", required = true) String status) throws Exception {
        System.out.println(" user recevied " + user.toString());
        return ResponseEntity.ok().build();


    }

    protected static class MyUser {

        private String userName;

        private String password;

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public MyUser(String userName) {
            this.userName = userName;
        }

        public MyUser(String userName, String password) {
            this.userName = userName;
            this.password = password;
        }

        @Override
        public String toString() {
            return "MyUser{" +
                    "userName='" + userName + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }

        public MyUser() {
        }

    }
}

My Controller Test :

package com.example.stackoverflowsecurityissue;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class StackoverflowSecurityIssueApplicationTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void performGetReq() throws Exception {
        ObjectMapper mapper=new ObjectMapper();
        mockMvc.perform(get("/request").
                param("userName","hello").param("password","hello").param("status","hello")).andExpect(status().isOk());
    }

}

output:

 user recevied MyUser{userName='hello', password='hello'}
Barath
  • 5,093
  • 1
  • 17
  • 42
  • we want to pass the custom User object (my User Class implements UserDetails .. `e.g: public class User extends BaseEntity implements UserDetails` . So I was having a helper class as below (Followed Refs: https://stackoverflow.com/questions/360520/unit-testing-with-spring-security ) Helper class : `public class MyUserHolder { public static MyUserDetails getUserDetails() { Authentication a = SecurityContextHolder.getContext().getAuthentication(); if (a == null) { return null; } else { return (MyUserDetails) a.getPrincipal();}}}` – sat1219 Sep 08 '17 at 16:23
  • pass the custom object as part of the mock mvc request ? then use .content(requestJson))? or else please update the question of ur controller handler method and secutiry configuration for more help – Barath Sep 08 '17 at 17:48
  • we are using SAML sso security and the sample controller handler method is something like this: `@ApiOperation(value = "this is to get requests", response = Response.class) @RequestMapping(value = "/request", method = RequestMethod.GET) public Response> getMyRequests(@Authenticated MyUser user, @RequestParam(value = "status", required = true) String status) throws Exception { List requests = myService.getUserRequestByStatus(user.getMyid(), status); return new Response>(Response.STATUS_SUCCESS, requests); }` – sat1219 Sep 08 '17 at 18:47
  • How do we pass the MyUser class object from junit test method here: Please let us know `mockMvc.perform(get("/test1/test2/test3/test4") .with(SecurityMockMvcRequestPostProcessors.user(new UsrHelpr().create())) .accept(MediaType.APPLICATION_JSON) .param("name", "testting")) .andExpect(status().isOk()).andReturn();` – sat1219 Sep 08 '17 at 18:49
  • Here is the gist I created . Please go through https://gist.github.com/59082f4f2b8a02d40c64937b17cbda95.git. Also updated the answer. Howwever I have no idea what @Authenticated do, so make it work accordingly – Barath Sep 08 '17 at 19:19
  • hi , I see you have defined ObjectMapper, but not passed/used in test method : `@Test public void performGetReq() throws Exception { ObjectMapper mapper=new ObjectMapper(); mockMvc.perform(get("/request"). param("userName","hello").param("password","hello").param("status","hello")).andExpect(status().isOk()); }` – sat1219 Sep 11 '17 at 15:13
  • `@barath` the above solution worked for us , Thanks for helping us. please post it as answer so that I can up vote it. Thank you once again. – sat1219 Sep 11 '17 at 19:00
  • @sat1219 I have updated my answer with the gist and first few lines talk about it. – Barath Sep 12 '17 at 02:24
  • `@Barath` please you post the gist as an answer , so that i can up vote it .Thank you Barath. – sat1219 Sep 12 '17 at 18:46
  • @sat1219 if this answer helped you, please upvote or accept it – Barath Sep 23 '17 at 04:08