I am doing a unit test for my controller using @WebMvcTest
in my unit test. My controller retrieves RequestAttributes
data from RequestContextHolder
:
RequestContextHolder.currentRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_REQUEST)
The data stored here is set in the interceptor:
RequestAttributes reqAttr = RequestContextHolder.currentRequestAttributes();
reqAttr.setAttribute(name, value, RequestAttributes.SCOPE_REQUEST);
RequestContextHolder.setRequestAttributes(reqAttr, true);
In my controller unit test, the interceptor is not running so I tried to set the request attributes before running my test but I am getting this error:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I have tried this answer https://stackoverflow.com/a/9419859/5545327. I added:
@Mock
private RequestAttributes attrs;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
RequestContextHolder.setRequestAttributes(attrs);
}
@Test
public void testController() {
when(requestAttributes.getAttribute(eq("<attribute name>"),
eq(RequestAttributes.SCOPE_REQUEST))).thenReturn(<mockReturn>);
// do your test...
}
But it is not working. The error is gone but the controller is getting null
value from the RequestContextHolder
. By the way I am testing my controller by doing this:
mockMvc.perform(post("<url>").content("<post params here>")).andExpect(status().isOk());
where mockMvc
is from @WebMvcTest
.
Note: I have a different class for integration test that is why I am using @WebMvcTest
here instead of @SpringBootTest
I am hoping you can give a descriptive answer since I am also quite new to Spring.
Thanks!
Edit:
- I can't simply put the data in the actual HttpRequest attribute. If I am not mistaken, the HttpRequest attributes are not automatically added as a request attribute in
RequestContextHolder
. Also, the data that I need is not from the HttpRequest but based on the HttpRequest. And I am mocking it since I know the actual request since this is my unit test.
Code looks like this:
@RunWith(SpringRunner.class)
@WebMvcTest
@OverrideAutoConfiguration(enabled = true)
@ActiveProfiles("test")
public abstract class BaseControllerTest {
@Autowired
protected MockMvc mockMvc;
}
public class ControllerTest extends BaseControllerTest {
@Test
public void testControllerMethod() {
mockMvc.perform(post("<url>").content("<post params here>")).andExpect(status().isOk());
// some more codes here
}
}
public class Controller {
@PostMapping
public String controllerMethod() {
// some more codes here
Object myObject = RequestContextHolder.currentRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_REQUEST);
// some more codes here
}
}