Java 请求作用域bean在使用Cucumber的Spring测试中不起作用

Java 请求作用域bean在使用Cucumber的Spring测试中不起作用,java,spring,cucumber,Java,Spring,Cucumber,我有一个基于Spring4.3.28(即不是SpringBoot!)的应用程序,我想将集成测试迁移到Cucumber 我遵循了这一点,并将其改编为《平原之春》 到目前为止,我编写的测试工作正常(Spring上下文已初始化等),但一旦涉及到请求范围的bean,它们就会停止工作: Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attribu

我有一个基于Spring4.3.28(即不是SpringBoot!)的应用程序,我想将集成测试迁移到Cucumber

我遵循了这一点,并将其改编为《平原之春》

到目前为止,我编写的测试工作正常(Spring上下文已初始化等),但一旦涉及到请求范围的bean,它们就会停止工作:

Caused by: 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/DispatcherPortlet: In this case, use 
RequestContextListener or RequestContextFilter to expose the current request.
我已经创建了一个小的 这试图重现问题

有一个名为AppConfig的上下文配置类:


@配置
公共类AppConfig{
@豆子
@Scope(“request”)//删除此行时,测试成功
公共示例服务示例服务(){
返回新的ExampleService();
}
@Bean(“依赖项”)
@Scope(“request”)//删除此行时,测试成功
公共字符串依赖项bean(){
返回“依赖bean”;
}
}
ExampleService是请求范围的,并获得一个由@Autowired注入的请求范围bean:

公共类示例服务{
@自动连线
@限定符(“依赖项”)
字符串依赖bean;
公共字符串进程(){return“我有一个”+dependencyBean;}
}
对于测试,我有一个Spring注释的超类:

@ContextConfiguration(classes=AppConfig.class)
@黄瓜构型
@WebAppConfiguration
公共类测试库{
@自动连线
公共服务被测试;
}
还有一个运行正常的普通Spring测试:

@RunWith(SpringRunner.class)
公共类ExampleServicePlainSpringTest扩展了TestBase{
@试验
处理数据时公共无效结果应返回(){
assertThat(this.underTest.process()).isEqualTo(“我有一个依赖bean”);
}
}
Cucumber测试由以下测试类存根执行:

@RunWith(Cucumber.class)
公共类ExampleServiceCucumberTest扩展了TestBase{}
实际步骤定义如下:

公共类CucumberStepDefinitions扩展了TestBase{
私有字符串结果;
@当(“我处理数据”)
public void iProcessData(){
结果=此.underTest.process();
}
@然后(“应返回结果”)
公共无效检查结果(){
assertThat(result.isEqualTo(“我有一个依赖bean”);
}
}
Cucumber的.feature文件位于src/test/resources目录下,与步骤定义类同名:

Feature: Example

  Scenario: Example service bean returns dependency
    When I process data
    Then the result should be returned
通常,当我遇到“找不到线程绑定的请求”错误时,这是因为
@WebAppConfiguration
注释丢失,或者当我试图将请求范围的bean注入非请求范围的bean时。但这里的情况并非如此。
我做错了什么?

我找到了解决方法;更新的代码在问题链接的github存储库中

使用
SpringRunner
时,请求上下文在
ServletTestExecutionListener
中初始化,该列表隐式添加到测试的
TestExecutionListener
列表中。 初始化在该侦听器的
beforeTestMethod()
方法中进行

然而,正如@M.p.Korsanje在评论中正确地指出的那样(谢谢!),Cucumber没有测试方法,因此永远不会执行
beforeTestMethod()

我的解决方案是将
ServletTestExecutionListener
的自定义子类添加为
TestExecutionListener
,该子类将
beforeTestClass()
调用委托给
beforeTestMethod()

公共类ClassLevelServletTestExecutionListener扩展了ServletTestExecutionListener{
@凌驾
public void beforeTestClass(TestContext TestContext)引发异常{
super.beforeTestMethod(testContext);
}
@凌驾
公共void后测试类(TestContext TestContext)引发异常{
super.postertestmethod(testContext);
}
}
示例服务黄瓜测试中

@ContextConfiguration(类={AppConfig.class})
@黄瓜构型
@WebAppConfiguration
@TestExecutionListeners(ClassLevelServletTestExecutionListener.class)
//扩展Spring类以获取默认的TestExecutionListeners
公共类TestBase扩展了AbstractJUnit4SpringContextTests{
@自动连线
公共服务被测试;
}

一目了然,一切都是正确的。Cucumber使用Springs TestContextManager,但不会触发其before/after方法挂钩,因为Cucumber没有一个方法。您可能需要在测试中创建请求上下文或向Cucumber提交修复。很好的破解!您介意在github上创建一个问题吗?我认为应该这样做无需黑客攻击即可获得适当的支持。