【问题标题】:How to mock HttpServletRequest with Headers?如何使用标头模拟 HttpServletRequest?
【发布时间】:2016-05-19 05:21:33
【问题描述】:

我正在使用MockitoJUnit 来测试应用程序。我需要在模拟时将标题添加到HttpServletRequest。这是我第一次使用模拟概念来测试应用程序。在使用这个模拟概念时,我们如何为请求对象设置标头?

应用代码

@Produces({ MediaType.APPLICATION_JSON })
@Path("/devices")
public class DvrRestService {
    private static final Logger logger = LoggerFactory.getLogger(DvrRestService.class);

    private DvrMiddleService dvrMiddleService;

    @Inject
    public DvrRestService(DvrMiddleService dvrMiddleService) {
        this.dvrMiddleService = dvrMiddleService;
    }

    @GET 
    @Path("/{deviceId}/metadata")
    public Response getDeviceMetadata(@Context HttpServletRequest request, @PathParam("deviceId") String deviceId,
        @RequiredSession final Session session) {

        try {
            public static String[] REQUEST_HEADERS = { "if-none-match" };
            List<String> requiredHeaders = Lists.newArrayList(REQUEST_HEADERS);
            Map<String, String> headers = new HashMap<String, String>();

            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) { // here gettting NullPointerException

                String headerName = headerNames.nextElement();
                if (requiredHeaders.contains(headerName.toLowerCase())) {
                    String value = request.getHeader(headerName);
                    if (value != null) {
                        headers.put(headerName, value);
                        System.out.println("headerName: " + headerName + ", Value: " + value);
                    }
                }
            }
            DvrResponse response = dvrMiddleService.getDeviceMetadata(deviceId.toUpperCase(), getHeaders(request));
            return processResponse(response.statusCode, response.getResponse(), DeviceMetadataResponse.class,
                response.getHeaders());
        } catch (Exception e) {
            return processErrorResponse(e, new DeviceMetadataResponse(), logger);
        }

    }
}

测试

public class DvrRestServiceTest {

    static DvrMiddleService dms;
    static HttpServletRequest request;
    static Session session;
    static DvrRestService drs;
    public static final String DeviceId = "000004D42070";
    @BeforeClass
    public static void init(){
        dms = mock(DvrMiddleService.class);
        request = mock(HttpServletRequest.class);
        session = mock(Session.class);
        drs = new DvrRestService(dms);
    }
    @Test
    public void getDeviceMetadataTest(){
        Response rs = drs.getDeviceMetadata(request, DeviceId, session);
        assertEquals(Response.Status.OK, rs.getStatus());
    }
}

【问题讨论】:

  • 它的文档很棒,看看,你只需要写类似 Mockito.when(request.getHeaderNames()).thenReturn(...what you want...)

标签: java servlets junit mockito


【解决方案1】:

作为主体的起点和演示,您可以从以下 sn-p 开始。

// define the headers you want to be returned
Map<String, String> headers = new HashMap<>();
headers.put(null, "HTTP/1.1 200 OK");
headers.put("Content-Type", "text/html");

// create an Enumeration over the header keys
Enumeration<String> headerNames = Collections.enumeration(headers.keySet());

// mock HttpServletRequest
HttpServletRequest request = mock(HttpServletRequest.class);
// mock the returned value of request.getHeaderNames()
when(request.getHeaderNames()).thenReturn(headerNames);

System.out.println("demonstrate output of request.getHeaderNames()");
while (headerNames.hasMoreElements()) {
    System.out.println("header name: " + headerNames.nextElement());
}
    
// mock the returned value of request.getHeader(String name)
doAnswer(new Answer<String>() {
    @Override
    public String answer(InvocationOnMock invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        return headers.get((String) args[0]);
    }
}).when(request).getHeader("Content-Type");

System.out.println("demonstrate output of request.getHeader(String name)");
String headerName = "Content-Type";
System.out.printf("header name: [%s]   value: [%s]%n", 
        headerName, request.getHeader(headerName));
}

输出

demonstrate output of request.getHeaderNames()
header name: null
header name: Content-Type

demonstrate output of request.getHeader(String name)
header name: [Content-Type]   value: [text/html]

【讨论】:

  • @Sathish 如果它解决了您的问题,请接受答案。
  • 通过调用 java.util.Collections#enumeration 创建枚举不是更短吗?
  • @473183469 是的。你说的对。 Enumeration&lt;String&gt; headerNames = Collections.enumeration(headers.keySet()) 会更短更智能。 ;-)
  • mock(HttpServletRequest.class) 对我不起作用。我可以请您分享您指的是哪个版本的 Mockito 吗?我正在使用 mockito-core-3.2.4
  • 哇!谢谢!!我从.m2 中删除了jar 并再次下载。那行得通。
【解决方案2】:

对于HttpServletRequest,我建议使用功能齐全的模拟类型,而不是直接使用 Mockito 模拟来模拟它。 spring-test 库有 MockHttpServletRequest 用于此目的:

@BeforeClass
public static void init(){
    // ...

    MockHttpServletRequest mockRequest = new MockHttpServletRequest();
    mockRequest.addHeader("Content-Type", "text/html");
    mockRequest.addHeader("if-none-match", "*");
    mockRequest.addHeader("customHeader", "customValue");

    this.request = mockRequest;
}

基本原理

HttpServletRequest 是一个复杂的接口,包含超过 20 种方法,它们之间有明确定义的相互作用。从库中为HttpServletRequest 使用功能齐全的模拟类型可以简化模拟,无需仔细模拟您正在使用的方法。

这种方法的一个优点是它在面对未来使用类上的其他方法获取相同信息的重构时更具弹性。在检索HttpServletRequest 中的“if-none-match”标头的情况下,我看到可以合法地用于检索标头的三种不同方法:getHeader(String name)getHeaders(String name)getHeaderNames()。此外,getHeadergetHeaders 的参数不区分大小写(“if-none-match”、“If-None-Match”等返回相同的结果),因此任何可能的参数大小写都会是正确的。直接模拟很可能支持这一点,尽管它涉及额外的样板代码,这会使测试复杂化并使其不那么明显。

spring-test 库中的 MockHttpServletRequest 类模拟此接口,并允许通过简单的 API 设置标头和其他值。虽然该库是为测试Spring 应用程序而设计的,但MockHttpServletRequest 类独立于任何特定于 Spring 的功能,即使应用程序不使用 Spring,它也应该完全可用。

【讨论】:

    【解决方案3】:

    这在我的情况下有效

    mockMvc.perform(post("<<url>>").content("<<jsonStrig>>").header("key", "value"));
    

    也可以用于get请求。

    【讨论】:

      【解决方案4】:

      我知道 OP 正在使用 Mockito。这个答案适用于那些使用 spock 的人。你可以很容易地做到这一点。

      class MyTestSpec extends Specification {
      
          HttpServletRequest request = Mock()
          MyTestClass myTestClass = new MyTestClass()
      
          def 'my test'() {
              setup:
              String expectedHeader = "x-mycustom-header"
      
              when:
              String someResult = myTestClass.someTestMethod()
      
              then:
              // here is where you return your header from the mocked request
              1 * request.getHeader(_ as String) >> expectedHeader
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-08
        • 1970-01-01
        • 2020-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多