【问题标题】:Spring MVC and JBehave. Cannot get @Autowired beans in *Steps.java classSpring MVC 和 JBehave。无法在 *Steps.java 类中获取 @Autowired bean
【发布时间】:2015-04-11 11:41:40
【问题描述】:

我使用 Spring MVC 有一段时间,并使用了 JUnit。当我测试服务或 dao 时,我使用 @Autowired 注解进行 bean 注入,效果很好。请注意,我在测试和应用程序中使用相同的配置文件,以避免在测试运行后配置错误。

现在我必须使用 JBehave 进行服务层测试。我的 Spring MVC 已经有域、DAO、服务层的包。我还为 DAO 和服务创建了示例 JUnit 测试。但是 JBehave 没有运气。我使用了http://jbehave.org/ 中的“五步概述”,并且能够在没有@Autowired bean 的情况下运行JBehave 测试并且它成功运行、生成报告等等。现在我想将 DAO 和 Service 层中的 @Autowired bean 添加到 *Steps.java,但它们似乎没有在运行时实例化。

我还用 Google 搜索并查看了来自 http://jbehave.org/ 的 Spring 示例,但我发现所有示例都不起作用,并且 jbehave.org 中的示例对我来说看起来很乱。

所以现在我在 Spring Tool Suite (Eclipse) 的 MAVEN 上构建了 Spring MVC、Hibernate、JUnit、JBehave 的工作配置。问题是:如何在 *Steps.java 类中为 JBehave 测试使用 @Autowired 对象。

我不知道我要在这里放什么数据,所以如果有不足的地方请告诉我,我会添加它。

admin_service_story.story

Scenario: There is 0 in DB

Given In database there are 0 goods
When The controller calls list method of service
Then service returns with 0 elements list

AdminServiceStory.java // 我将它作为 JUnit 测试运行

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/META-INF/spring/root-context.xml")
public class AdminServiceStory extends JUnitStory{

    private final CrossReference xref = new CrossReference();

    public AdminServiceStory() {
        configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
                .doIgnoreFailureInView(true).useThreads(2).useStoryTimeoutInSecs(60);
        // Uncomment to set meta filter, which can also be set via Ant or Maven
        // configuredEmbedder().useMetaFilters(Arrays.asList("+theme parametrisation"));
    }

    @Override
    public Configuration configuration() {
        Class<? extends Embeddable> embeddableClass = this.getClass();
        Properties viewResources = new Properties();
        viewResources.put("decorateNonHtml", "true");
        // Start from default ParameterConverters instance
        ParameterConverters parameterConverters = new ParameterConverters();
        // factory to allow parameter conversion and loading from external
        // resources (used by StoryParser too)
        ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(),
                new LoadFromClasspath(embeddableClass), parameterConverters);
        // add custom converters
        parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
                new ExamplesTableConverter(examplesTableFactory));

        return new MostUsefulConfiguration()
                .useStoryControls(new StoryControls().doDryRun(false).doSkipScenariosAfterFailure(false))
                .useStoryLoader(new LoadFromClasspath(embeddableClass))
                .useStoryParser(new RegexStoryParser(examplesTableFactory))
                .useStoryPathResolver(new UnderscoredCamelCaseResolver())
                .useStoryReporterBuilder(
                        new StoryReporterBuilder()
                                .withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
                                .withDefaultFormats().withPathResolver(new ResolveToPackagedName())
                                .withViewResources(viewResources).withFormats(Format.CONSOLE, Format.STATS, Format.TXT, Format.HTML, Format.XML)
                                .withFailureTrace(true).withFailureTraceCompression(true).withCrossReference(xref))
                .useParameterConverters(parameterConverters)
                // use '%' instead of '$' to identify parameters
                .useStepPatternParser(new RegexPrefixCapturingPatternParser("%"))
                .useStepMonitor(xref.getStepMonitor());
    }

    @Override
    public InjectableStepsFactory stepsFactory() {
        return new InstanceStepsFactory(configuration(), new AdminServiceSteps());
    }
}

AdminServiceSteps.java

我用异常标记了字符串:goodDAO.save(good);//!!!这里发生异常 java.lang.NullPointerException !!!

@Component
public class AdminServiceSteps {
    private static final String CATALOG_NUMBER_PREFIX = "Num_";
    private static final String NAME_PREFIX = "Good name_";
    private static final String DESCRIPTION_PREFIX = "Description_";

    @Autowired
    private AdminService adminService;

    @Autowired
    private GoodDAO goodDAO;

    List<Good> goodsList;

    @Transactional
    @Given("In database there are %num goods")
    public void putGoodsInDB(int num) {
        Good good;
        for (Integer i = 0; i< num; i++){
            good = new Good();
            good.setCatalogNumber(CATALOG_NUMBER_PREFIX+Integer.toString(i));
            good.setDescription(DESCRIPTION_PREFIX+Integer.toString(i));
            good.setName(NAME_PREFIX+Integer.toString(i));
            goodDAO.save(good);//!!! here exception occurs java.lang.NullPointerException !!!
        }
    }

    //@Transactional
    @When("The controller calls list method of service")
    public void controllerCallsList() {
        //goodsList = adminService.list();
    }

    @Then("service returns with %num elements list")
    public void checkGoodsListSize(int num) {
        //assertEquals("Assert list size", num, goodsList.size());
    }
}

Augusto 感谢您的想法。让我们看看发生了什么。我变了

public class AdminServiceStory extends JUnitStory implements ApplicationContextAware {

在类正文中:

...

    ApplicationContext springContext; 

    @Override
    public InjectableStepsFactory stepsFactory() {
        return new SpringStepsFactory(configuration(), springContext);
     }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        springContext = applicationContext;
    }

当我查看调试器时,看起来 InjectableStepsFactory() 在 setApplicationContext() 之前运行,所以 springContext 变量尚未设置。

所以我明白了

java.lang.NullPointerException
    at org.jbehave.core.steps.spring.SpringStepsFactory.stepsTypes(SpringStepsFactory.java:32)
    at org.jbehave.core.steps.AbstractStepsFactory.createCandidateSteps(AbstractStepsFactory.java:34)
    at org.jbehave.core.embedder.StoryManager.runBeforeOrAfterStories(StoryManager.java:90)
    at org.jbehave.core.embedder.StoryManager.runStories(StoryManager.java:75)
    at org.jbehave.core.embedder.Embedder.runStoriesAsPaths(Embedder.java:203)
    at org.jbehave.core.junit.JUnitStory.run(JUnitStory.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

【问题讨论】:

    标签: spring-mvc autowired jbehave


    【解决方案1】:

    您正在尝试以我不熟悉的方式使用 spring 和 JBheave,甚至可能无法通过大量工作(以及来自 JBehave 内部的知识)使其工作。

    有一个明显的问题,您创建的AdminServiceSteps 实例不是来自Spring 上下文。你可以尝试用这种方式替换 StepsFactory

    @Override
    public InjectableStepsFactory stepsFactory() {
        return new SpringStepsFactory(configuration(), springContext);
    }
    

    SpringStepsFactory 类是 JBehave-spring 集成的一部分

    【讨论】:

    • 是的,我想你在这里:“你创建的 AdminServiceSteps 实例不是来自 Spring 上下文”。但不知道该怎么做。无论如何,当我继续时,我得到了异常。将在第一篇文章中详细说明此评论
    • 尝试使用我上面提到的类SpringStepsFactory。这将使用具有自动装配值的正确实例。
    • 我做到了,但也遇到了问题。看看我最初的消息的部分编辑:“Augusto 谢谢你的想法。让我们看看发生了什么。我改变了”。
    猜你喜欢
    • 2012-11-03
    • 2018-04-03
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    相关资源
    最近更新 更多