请求范围的Bean在Cucumber的春季测试中不起作用

问题描述

我有一个基于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 试图重现问题。

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


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

对于测试,我有一个带有Spring注释的超类:

@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