当控制器依赖于请求上下文时,无法使用@WebMvcTest对控制器进行单元测试

时间:2018-12-28 08:17:34

标签: java spring unit-testing spring-mvc controller

我正在使用单元测试中的@WebMvcTest对控制器进行单元测试。我的控制器从RequestAttributes检索了RequestContextHolder数据:

RequestContextHolder.currentRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_REQUEST)

此处存储的数据在拦截器中设置:

RequestAttributes reqAttr = RequestContextHolder.currentRequestAttributes();
reqAttr.setAttribute(name, value, RequestAttributes.SCOPE_REQUEST);
RequestContextHolder.setRequestAttributes(reqAttr, true);

在我的控制器单元测试中,拦截器未运行​​,因此我尝试在运行测试之前设置请求属性,但出现此错误:

  

java.lang.IllegalStateException:未找到线程绑定请求:您是在实际Web请求之外引用请求属性,还是在原始接收线程之外处理请求?如果您实际上是在Web请求中操作并且仍然收到此消息,则您的代码可能正在DispatcherServlet外部运行:在这种情况下,请使用RequestContextListener或RequestContextFilter公开当前请求。

我已经尝试过此答案https://stackoverflow.com/a/9419859/5545327。我加了:

@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...
}

但是它不起作用。错误消失了,但是控制器正在从null获取RequestContextHolder的值。顺便说一下,我正在通过以下方式测试我的控制器:

mockMvc.perform(post("<url>").content("<post params here>")).andExpect(status().isOk());

mockMvc来自@WebMvcTest

注意:我有一个用于集成测试的类,这就是为什么我在这里使用@WebMvcTest而不是@SpringBootTest

的原因

由于我对Spring还很陌生,所以我希望您能提供一个描述性的答案。

谢谢!

编辑:

  • 我不能简单地将数据放入实际的HttpRequest属性中。如果我没有记错的话,HttpRequest属性不会自动添加为RequestContextHolder中的请求属性。另外,我需要的数据不是来自HttpRequest,而是基于HttpRequest。我嘲笑它,因为我知道实际的请求,因为这是我的单元测试。

代码如下:

@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
    }
}

0 个答案:

没有答案