Java 无法在JBehave中具有公共生命周期步骤的不同故事之间共享web驱动程序实例
我有两个不同的步骤类,它们在步骤之前和步骤之后具有共同的生命周期。因此,我创建了一个通用的step类,该类将webdriver初始化和清理代码作为方法前后的生命周期。该公共类由两个步骤定义类扩展。在运行这些故事时,我在第二步类中访问web驱动程序时看到空指针异常。进一步调试我注意到,每当故事文件中出现场景时,都会使用first step类对象调用公共步骤 我的故事档案1Java 无法在JBehave中具有公共生命周期步骤的不同故事之间共享web驱动程序实例,java,jbehave,Java,Jbehave,我有两个不同的步骤类,它们在步骤之前和步骤之后具有共同的生命周期。因此,我创建了一个通用的step类,该类将webdriver初始化和清理代码作为方法前后的生命周期。该公共类由两个步骤定义类扩展。在运行这些故事时,我在第二步类中访问web驱动程序时看到空指针异常。进一步调试我注意到,每当故事文件中出现场景时,都会使用first step类对象调用公共步骤 我的故事档案1 Meta: @author prasanta biswas @theme UI Test Narrative: As a F
Meta:
@author prasanta biswas
@theme UI Test
Narrative:
As a Facebook User
In order to update my status
I want to login to my Facebook account
So that I can update my status message
Lifecycle:
Before:
Scope: SCENARIO
Given I initialize my chrome browser instance
After:
Scope: SCENARIO|STORY
Outcome: ANY
Given I cleanup my browser instance
Scenario: Update Facebook status message
Meta:
@type positive
@data valid
@app facebook
Given I have a Facebook account
And I open Facebook in my web browser with the <url>
And I login to Facebook with <username> and <password>
Then I check if status message box is present in the homepage after successful login
When I put my status <message> in the status box
And I click post button
Then I should see my new status <message> in my news feeds
Examples:
|username|password|url|message|
|VALID_USERNAME|VALID_PASSWORD|https://www.facebook.com|Hi Facebook|
我的第一步定义类:
package io.jbehavetutorials.steps.facebook;
import io.jbehavetutorials.appmodule.facebook.FacebookApp;
import io.jbehavetutorials.constants.Browser;
import io.jbehavetutorials.steps.common.CommonSteps;
import io.jbehavetutorials.testutility.BrowserFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jbehave.core.annotations.*;
import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import java.net.MalformedURLException;
/**
* Created by prasantabiswas on 21/05/18.
*/
public class FacebookStatusPost extends CommonSteps{
FacebookApp facebookApp;
Logger logger = LogManager.getLogger(FacebookStatusPost.class);
@Given("I have a Facebook account")
@Pending
public void iHaveAFacebookAccount()
{
try {
facebookApp = new FacebookApp(webDriver); // Working perfectly here
Assert.assertTrue("Facebook object creation failed",facebookApp!=null);
}
catch (Exception e)
{
logger.error("Error",e);
}
}
}
package io.jbehavetutorials.steps.wallethub;
import io.jbehavetutorials.appmodule.wallethub.WalletHubApp;
import io.jbehavetutorials.constants.Browser;
import io.jbehavetutorials.steps.common.CommonSteps;
import io.jbehavetutorials.testutility.BrowserFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jbehave.core.annotations.*;
import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.net.MalformedURLException;
/**
* Created by prasantabiswas on 21/05/18.
*/
public class WalletHubReviewInsurance extends CommonSteps {
WalletHubApp wallethubApp;
int reviewCount = 0;
Logger logger = LogManager.getLogger(WalletHubReviewInsurance.class);
@Given("I have a WalletHub test account")
public void iHaveAWallerHubTestAccount()
{
try{
wallethubApp = new WalletHubApp(webDriver);//Getting null pointer here
}
catch (Exception e)
{
logger.error("Error",e);
}
}
}
我的第二步定义类:
package io.jbehavetutorials.steps.facebook;
import io.jbehavetutorials.appmodule.facebook.FacebookApp;
import io.jbehavetutorials.constants.Browser;
import io.jbehavetutorials.steps.common.CommonSteps;
import io.jbehavetutorials.testutility.BrowserFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jbehave.core.annotations.*;
import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import java.net.MalformedURLException;
/**
* Created by prasantabiswas on 21/05/18.
*/
public class FacebookStatusPost extends CommonSteps{
FacebookApp facebookApp;
Logger logger = LogManager.getLogger(FacebookStatusPost.class);
@Given("I have a Facebook account")
@Pending
public void iHaveAFacebookAccount()
{
try {
facebookApp = new FacebookApp(webDriver); // Working perfectly here
Assert.assertTrue("Facebook object creation failed",facebookApp!=null);
}
catch (Exception e)
{
logger.error("Error",e);
}
}
}
package io.jbehavetutorials.steps.wallethub;
import io.jbehavetutorials.appmodule.wallethub.WalletHubApp;
import io.jbehavetutorials.constants.Browser;
import io.jbehavetutorials.steps.common.CommonSteps;
import io.jbehavetutorials.testutility.BrowserFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jbehave.core.annotations.*;
import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.net.MalformedURLException;
/**
* Created by prasantabiswas on 21/05/18.
*/
public class WalletHubReviewInsurance extends CommonSteps {
WalletHubApp wallethubApp;
int reviewCount = 0;
Logger logger = LogManager.getLogger(WalletHubReviewInsurance.class);
@Given("I have a WalletHub test account")
public void iHaveAWallerHubTestAccount()
{
try{
wallethubApp = new WalletHubApp(webDriver);//Getting null pointer here
}
catch (Exception e)
{
logger.error("Error",e);
}
}
}
故事地图类:
package io.jbehavetutorials;
import io.jbehavetutorials.steps.facebook.FacebookStatusPost;
import io.jbehavetutorials.steps.wallethub.WalletHubReviewInsurance;
import io.jbehavetutorials.steps.weatherapi.WeatherAPITest;
import org.jbehave.core.embedder.StoryControls;
import org.jbehave.core.junit.JUnitStories;
import java.text.SimpleDateFormat;
import java.util.List;
import org.jbehave.core.Embeddable;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.i18n.LocalizedKeywords;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.model.ExamplesTableFactory;
import org.jbehave.core.model.TableTransformers;
import org.jbehave.core.parsers.RegexStoryParser;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.reporters.SurefireReporter;
import org.jbehave.core.steps.*;
import org.jbehave.core.steps.ParameterConverters.DateConverter;
import org.jbehave.core.steps.ParameterConverters.ExamplesTableConverter;
import static org.jbehave.core.io.CodeLocations.codeLocationFromClass;
import static org.jbehave.core.reporters.Format.CONSOLE;
import static org.jbehave.core.reporters.Format.HTML;
import static org.jbehave.core.reporters.Format.TXT;
import static org.jbehave.core.reporters.Format.XML;
/**
* <p>
* {@link Embeddable} class to run multiple textual stories via JUnit.
* </p>
* <p>
* Stories are specified in classpath and correspondingly the {@link LoadFromClasspath} story loader is configured.
* </p>
*/
public class StoryMap extends JUnitStories {
public StoryMap() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(1);
// configuredEmbedder().useMetaFilters(Arrays.asList("+type negative"));
}
@Override
public Configuration configuration() {
Class<? extends Embeddable> embeddableClass = this.getClass();
// Start from default ParameterConverters instance
ParameterConverters parameterConverters = new ParameterConverters();
// Start from default ParameterControls instance
ParameterControls parameterControls = new ParameterControls();
// factory to allow parameter conversion and loading from external resources (used by StoryParser too)
ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(), new LoadFromClasspath(embeddableClass),parameterConverters,parameterControls, new TableTransformers());
// add custom converters
parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
new ExamplesTableConverter(examplesTableFactory));
return new MostUsefulConfiguration()
//.usePendingStepStrategy(new FailingUponPendingStep())
.useStoryControls(new StoryControls().doDryRun(false))
.useStoryLoader(new LoadFromClasspath(embeddableClass))
.useStoryParser(new RegexStoryParser(examplesTableFactory))
// .useStoryParser(new GherkinStoryParser())
.useStoryReporterBuilder(new StoryReporterBuilder()
.withSurefireReporter(new SurefireReporter(embeddableClass))
.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
.withDefaultFormats()
.withFormats(CONSOLE, TXT, HTML, XML)
.withFailureTrace(true)
.withFailureTraceCompression(true))
.useParameterConverters(parameterConverters)
.useParameterControls(parameterControls);
}
@Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new FacebookStatusPost(), new WalletHubReviewInsurance(), new WeatherAPITest());
// return new ScanningStepsFactory(configuration(),"io.jbehavetutorials.steps"); //requires reflection dependency
}
@Override
protected List<String> storyPaths() {
return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()), "**/*.story", "**/excluded*.story");
}
}
package io.jbehave教程;
导入io.jbehavetutorials.steps.facebook.FacebookStatusPost;
导入io.jbehavetutorials.steps.wallethub.WalletHubReviewInsurance;
导入io.jbehavetutorials.steps.weatherapi.WeatherAPITest;
导入org.jbehave.core.embedder.StoryControls;
导入org.jbehave.core.junit.JUnitStories;
导入java.text.simpleDataFormat;
导入java.util.List;
导入org.jbehave.core.embeddeble;
导入org.jbehave.core.configuration.configuration;
导入org.jbehave.core.configuration.mostuseveConfiguration;
导入org.jbehave.core.i18n.LocalizedKeywords;
导入org.jbehave.core.io.CodeLocations;
导入org.jbehave.core.io.LoadFromClasspath;
导入org.jbehave.core.io.StoryFinder;
导入org.jbehave.core.model.ExamplesTableFactory;
导入org.jbehave.core.model.TableTransformers;
导入org.jbehave.core.parsers.RegexStoryParser;
导入org.jbehave.core.reporters.StoryReporterBuilder;
导入org.jbehave.core.reporters.SurefireReporter;
导入org.jbehave.core.steps.*;
导入org.jbehave.core.steps.ParameterConverters.DateConverter;
导入org.jbehave.core.steps.ParameterConverter.ExamplesTableConverter;
导入静态org.jbehave.core.io.CodeLocations.codeLocationFromClass;
导入静态org.jbehave.core.reporters.Format.CONSOLE;
导入静态org.jbehave.core.reporters.Format.HTML;
导入静态org.jbehave.core.reporters.Format.TXT;
导入静态org.jbehave.core.reporters.Format.XML;
/**
*
*{@link embeddeble}类通过JUnit运行多个文本故事。
*
*
*故事在类路径中指定,并相应地配置了{@link LoadFromClasspath}故事加载器。
*
*/
公共类故事图扩展了JUnitStores{
公共故事地图(){
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(1);
//configuredEmbedder().useMetaFilters(Arrays.asList(“+type negative”);
}
@凌驾
公共配置(){
类一个解决方法是使驱动程序实例在CommonSteps
类中保持静态。这不是一个具体的解决方案,因为它不能与多个线程同时运行故事一起使用,因为它会使驱动程序实例易受攻击。问题是扩展CommonSteps
的每个类都有自己的insta您应该为webDriver实例创建一些存储,这些存储将在所有步骤实现中共享。但这不是一个错误。它应该为每个步骤类创建单独的对象来调用其父类方法。但是,它被其他类对象调用只是为了调用生命周期方法。不,这不是一个bug。这些是OOP的基本原则,您可以在没有JBehave的情况下模拟相同的行为:父类状态不会在子类之间共享,除非它是静态的。这不是关于共享状态,而是从其子类调用父类init函数,以便每个子对象都有自己的状态。例如,FacebookStatusPost和WalletHubReviewInsurance类应分别从各自的实例中调用CommonSteps中的setUp和tearDown方法,以便每个对象都可以使用其自己初始化的webDriver实例。但在JBehave中,这是不同的。对于两个子类步骤,父类方法仅从其一个子类的对象调用s执行。因此webDriver对于其他步骤类对象为空。您声明了两个步骤类实例,它们声明了相同的步骤:new FacebookStatusPost(),new WalletHubReviewInsurance()
。当您运行场景时,将调用第一个匹配的步骤。在您的示例步骤中(给定我初始化我的chrome浏览器实例)始终从FacebookStatusPost
调用,因此此实例中的webDriver
始终被初始化,但从不从WalletHubReviewInsurance