JBe如何在步骤之间保持对象状态

时间:2016-03-14 05:54:22

标签: java junit bdd jbehave

我正在使用JBehave编写BDD集成测试。
问题:JBehave在执行单个步骤时清除对象状态(实例变量) 码: StepDefinition:

public class StepDefs {

    private String str;

    @Given("step represents a precondition to an $event")
    public void given(String event){
        str=event;
        System.out.println("Given: "+str);
    }

    @When("step represents the occurrence of the event")
    public void when() {
        System.out.println("When: "+str);
    }

    @Then("step represents the outcome of the event")
    public void then() {

    }
}

故事:

Sample story

Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development

Scenario:  A scenario is a collection of executable steps of different type
Given step represents a precondition to an event
When step represents the occurrence of the event
Then step represents the outcome of the event

JBehaveJUnitTestRunner:

@RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {

    private CrossReference xref = new CrossReference();

    public JBehaveTestsRunner() {
        configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
                .doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
    }

    @Override
    public Configuration configuration() {
        Properties viewResources = new Properties();
        viewResources.put("decorateNonHtml", "true");
        return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
                .useStoryReporterBuilder(
                        new StoryReporterBuilder().withFormats(Format.HTML, Format.CONSOLE, Format.STATS)
                                .withViewResources(viewResources).withFailureTrace(true).withFailureTraceCompression(false)
                                .withCrossReference(xref));
    }

    @Override
    public InjectableStepsFactory stepsFactory() {
        return new ScanningStepsFactory(configuration(), "stepdefs");
    }

    @Override
    public List<String> storyPaths() {
        StoryFinder finder = new StoryFinder();
        return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Simple.story"), null);
    }
}

实际输出:

Processing system properties {}
Using controls EmbedderControls[batch=false,skip=false,generateViewAfterStories=true,ignoreFailureInStories=true,ignoreFailureInView=true,verboseFailures=true,verboseFiltering=false,storyTimeouts=300,threads=1,failOnStoryTimeout=false]

(BeforeStories)

Running story stories/Simple.story
Sample story
(stories/Simple.story)
Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development
Scenario: A scenario is a collection of executable steps of different type
**Given: event**
Given step represents a precondition to an event
**When: null**
When step represents the occurrence of the event
Then step represents the outcome of the event



(AfterStories)

Generating reports view to 'C:\WORKING\lunaworkspace\pkeautomation\target\jbehave' using formats '[html, console, stats, junitscenarioreporter]' and view properties '{decorateNonHtml=true}'
log4j:WARN No appenders could be found for logger (freemarker.cache).
log4j:WARN Please initialize the log4j system properly.
Reports view generated with 3 stories (of which 1 pending) containing 2 scenarios (of which 1 pending)

从输出中可以看出:在给定步骤中,我接受一个字符串参数,我将其初始化为实例变量&#34; str&#34;,同时将值打印到控制台我可以看到它成功。但是当第二步,即当步骤执行时,我得到null作为实例变量&#34; str&#34;的值。如何在执行单个步骤后让JBehave不清除对象的状态?

2 个答案:

答案 0 :(得分:2)

对于那些正在寻找这个问题答案的人,我确实通过JBehave谷歌团体社区的帮助找到了适当的解决方案。解决方案非常简单,而不是使用ScanningStepFactory使用InstanceStepsFactory,这应该保持对象的状态。链接到讨论:Google Group discussion

任何人来到这里寻求答案的片段:

package runner;

import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.CrossReference;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
//import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
//import org.jbehave.core.steps.ScanningStepsFactory;
import org.junit.runner.RunWith;

import de.codecentric.jbehave.junit.monitoring.JUnitReportingRunner;
import stepdefs.StepDefs;
//import stepdefs.BarStep;
//import stepdefs.FooStep;

@RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {

    private CrossReference xref = new CrossReference();

    public JBehaveTestsRunner() {
        configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
                .doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
    }

    @Override
    public Configuration configuration() {
        Properties viewResources = new Properties();
        viewResources.put("decorateNonHtml", "true");
        return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
                .useStoryReporterBuilder(new StoryReporterBuilder()
                        .withFormats(Format.HTML, Format.CONSOLE, Format.STATS).withViewResources(viewResources)
                        .withFailureTrace(true).withFailureTraceCompression(false).withCrossReference(xref));
    }

    /*@Override
    public List<CandidateSteps> candidateSteps() {
        return new InstanceStepsFactory(configuration(), new FooStep(), new BarStep(), new StepDefs())
                .createCandidateSteps();
    }*/

    @Override
    public InjectableStepsFactory stepsFactory() {
        return new InstanceStepsFactory(configuration(), new StepDefs());
        // return new ScanningStepsFactory(configuration(), "stepdefinitions");
    }

    @Override
    public List<String> storyPaths() {
        StoryFinder finder = new StoryFinder();
        return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Sample.story"),
                null);
    }
}

答案 1 :(得分:1)

我使用JBehave已经有一段时间了。您可能正在为每个ScanningStepsFactory电话创建新的stepsFactory()。尝试只在构造函数中创建其中一个然后传回该实例,这样就不会为每个调用创建一个新实例。

如果失败,请尝试使用示例here中的InstanceStepsFactory

public abstract class NoughtsAndCrossesStory extends JUnitStory {

    public NoughtsAndCrossesStory() {
        Configuration configuration = new MostUsefulConfiguration()
            .useStoryPathResolver(new UnderscoredCamelCaseResolver(""))
            .useStoryReporterBuilder(new StoryReporterBuilder()
                .withCodeLocation(CodeLocations.codeLocationFromClass(this.getClass()))
                .withDefaultFormats()
                .withFormats(CONSOLE, TXT)
                .withFailureTrace(true));
        useConfiguration(configuration);
        WindowControl windowControl = new WindowControl();
        addSteps(new InstanceStepsFactory(configuration,new GridSteps(windowControl), new BeforeAndAfterSteps(windowControl)).createCandidateSteps());
     }

}

您需要创建某种持久存储库对象来保存您的字符串(在上面的示例中,windowControl仍然存在)。

public class BeforeAndAfterSteps extends Steps {

    private final WindowControl windowControl;

    public BeforeAndAfterSteps(WindowControl windowControl) {
        this.windowControl = windowControl;
    }

    @BeforeScenario
    public void beforeScenarios() throws Exception {
        windowControl.reset();
    }

    @AfterScenario
    public void afterScenarios() throws Exception {
        windowControl.destroy();
    }
}

这使您不仅可以跨步骤保持状态,还可以在场景之间保持状态。请注意,这通常被认为是一种不好的做法;我在这里使用它来确保状态在场景之间保持不变,但理论上你可以使用它来例如在运行测试套件之前初始化默认数据。