问题描述
我有一个基于Spring 4.3.28的应用程序(即不是Spring Boot!),我想将集成测试迁移到Cucumber。
我遵循了这个tutorial,并将其改编成普通的Spring。
到目前为止,我编写的测试工作正常(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.
我创建了一个小的sample project 试图重现问题。
@Configuration
public class AppConfig {
@Bean
@Scope("request“) // when this line is removed,the test succeeds
public ExampleService exampleService() {
return new ExampleService();
}
@Bean("dependency")
@Scope("request") // when this line is removed,the test succeeds
public String dependencyBean() {
return "dependency bean";
}
}
ExampleService是基于请求范围的,并获取了一个由@Autowired注入的基于请求范围的bean:
public class ExampleService {
@Autowired
@Qualifier("dependency")
String dependencyBean;
public String process() { return "I have a "+dependencyBean; }
}
@ContextConfiguration(classes = AppConfig.class)
@CucumberContextConfiguration
@WebAppConfiguration
public class TestBase {
@Autowired
public ExampleService underTest;
}
还有一个普通的Spring测试可以很好地运行:
@RunWith(springrunner.class)
public class ExampleServicePlainspringTest extends TestBase {
@Test
public void whenProcessingDataThenResultShouldBeReturned() {
assertthat(this.underTest.process()).isEqualTo("I have a dependency bean");
}
}
黄瓜测试由该测试类存根执行:
@RunWith(Cucumber.class)
public class ExampleServiceCucumberTest extends TestBase {}
实际的黄瓜步骤定义在这里:
public class CucumberStepDeFinitions extends TestBase {
private String result;
@When("I process data")
public void iProcessData() {
result = this.underTest.process();
}
@Then("the result should be returned")
public void checkResult() {
assertthat(result).isEqualTo("I have a dependency 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存储库中。
使用<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Color Flipper</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<nav>
<div class="nav-center">
<ul class="nav-links">
<li>
<a href="index.html">Color Flipper</a>
</li>
<li>
<a href="hex.html">Simple Hex</a>
</li>
</ul>
</div>
</nav>
<main>
<div class="container">
<div class="container2" <h2>background color : <span class="color">
#f1f5f8
</span></h2>
</div>
<button class="btn-hero" id="btn">click me</button>
</div>
</main>
</body>
</html>
时,请求上下文在SpringRunner
中初始化,该上下文隐式添加到ServletTestExecutionListener
的列表中以进行测试。
初始化在该侦听器的TestExecutionListener
方法中进行。
但是,正如@ M.P.Korsanje在评论中正确指出的(谢谢!),Cucumber没有测试方法,因此beforeTestMethod()
永远不会执行。
我的解决方案是将beforeTestMethod()
的自定义子类添加为ServletTestExecutionListener
,该子类将TestExecutionListener
的调用委托给beforeTestClass()
:
beforeTestMethod()
在public class ClassLevelServletTestExecutionListener extends ServletTestExecutionListener {
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestMethod(testContext);
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
super.afterTestMethod(testContext);
}
}
中:
ExampleServiceCucumberTest