【问题标题】:Spring Boot HTTPServletRequest not properly available through testSpring Boot HTTPServletRequest 无法通过测试正确使用
【发布时间】:2016-01-13 19:03:15
【问题描述】:

我试图在这里搜索答案,但找不到。所以这里是:我正在使用 Spring Boot。我正在使用动态解析查询字符串

@RestController()
@RequestMapping("/processors")
public class ProcessorsController {

    protected static transient Logger log = LoggerFactory.getLogger(ProcessorsController.class);

    private Gson gson = new Gson();

    @Autowired
    HttpServletRequest request;

    private Options options = new Options();

    @Autowired
    ProcessorRepository processorRepository;

    //Inside a method, I am populating the Options<String, String> map using
    //request.getParameterMap() 

    @CrossOrigin
    @RequestMapping(value = "/{name}/run", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    String run(@RequestBody String input, @PathVariable("name") String name) {
        Validate.notEmpty(input, "The request body must contain an not empty text");
        return runProcessor(input, name);
    }

    private String runProcessor(String input, String name) {
        Validate.notEmpty(name, "The processor name cannot be empty");
        Processor processor = processorRepository.getProcessorCalled(name);
        addOptions();
        return processor.run(input, options);
    }

    private void addOptions() {
        request.getParameterMap().forEach((k, v) -> {
            if (!k.equals("text")) {
                if (v[0] != null && !v[0].isEmpty()) {
                    options.put(k, v[0]);
                }
            }
        });
    }
}

这在手动测试中效果很好,但我正在尝试编写单元测试。以下是示例:

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {HAL.class, ProcessorsController.class})
@WebAppConfiguration
public abstract class ProcessorsControllerAbstractTest {

    MockMvc mvc;

    @Autowired
    ProcessorRepository processorRepository;

    @Autowired
    HttpServletRequest request;

    @Autowired
    ProcessorsController processorsController;


    @Before
    public void setUp() throws Exception {
        processorsController.processorRepository = processorRepository;
        processorsController.request = request;
        mvc = MockMvcBuilders.standaloneSetup(processorsController).build();
    }
}

和 在实际测试类中

public class ProcessorsControllerTest extends ProcessorsControllerAbstractTest {
    //other test cases
    @Test
    public void testAddOptions() throws Exception {
        mvc.perform(MockMvcRequestBuilders.post("/processors/default/run").param("size", "500").content(input).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
        Assert.assertEquals("500", options.get("size"));
    }
}

我无法在request.getParameterMap() 获取请求对象值(例如size 之类的参数)。有什么办法可以访问它吗?如果不是,那么测试它的另一种方法是什么? 提前致谢!

【问题讨论】:

  • 您介意添加ProcessorsController 的代码吗?至少是类定义的注释和第一行?
  • @JonathanThoms 我刚刚编辑了代码。感谢您的关注!
  • 我猜这是由于请求的自动装配。 MockMvc 对此一无所知,因此不会在其上设置参数。尝试摆脱该字段并将其作为 ProcessorsController.run 方法的参数。
  • 您不应该自动连接HttpServletRequest,这是一个非常糟糕的主意。只需将其添加为方法参数并将其传递给所需的方法即可。您的控制器也有缺陷,因为您永远不应该将状态存储在实例变量中。 (如果有 2 个请求进来并修改单个 Options 实例会发生什么?)。另外,您为什么要进行手动解析?为什么不简单地让 Spring MVC 处理这个......你应该使用框架而不是围绕它。
  • 非常感谢您的帮助!

标签: java spring testing spring-boot


【解决方案1】:

您不应该自动连接HttpServletRequest,这是一个非常糟糕的主意。

而是将@RequestParam Map&lt;String,String&gt; params 添加到您的方法签名中,这将自动包含所有参数。如参考指南中的here 所述。

@CrossOrigin
@RequestMapping(value = "/{name}/run", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
String run(@RequestBody String input, @PathVariable("name") String name, @RequestParam Map<String, String> params) {
    Validate.notEmpty(input, "The request body must contain an not empty text");
    return runProcessor(input, name, params);
}

现在您的控制器也存在缺陷,因为将 Options 存储为实例变量。控制器是一个单例现在想象一下当 10 个请求同时开始修改这个实例时会发生什么。为此更改您的 runProcessoraddOptions 方法。

private String runProcessor(String input, String name, Map<String, String> params) {
    Validate.notEmpty(name, "The processor name cannot be empty");
    Processor processor = processorRepository.getProcessorCalled(name);
    Options options = new Options();
    addOptions(options, params);
    return processor.run(input, options);
}

private void addOptions(Options options, Map<String, String> params) {
    params.forEach((k, v) -> {
        if (!k.equals("text")) {
            if (v != null && !v.isEmpty()) {
                options.put(k, v);
            }
        }
    });
}

您可能希望将 addOptions 添加到 Options 类中(或者将其添加到构造函数中,以便您可以使用 Map&lt;String, String&gt; 构造 Options 实例。

【讨论】:

    猜你喜欢
    • 2019-03-26
    • 1970-01-01
    • 2018-01-27
    • 2021-12-21
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 2021-10-18
    • 2016-02-27
    相关资源
    最近更新 更多