java 在步骤定义文件之间共享相同的 selenium WebDriver
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31573676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sharing same selenium WebDriver between step definition files
提问by davidicus
Right now we're working on adopting Cucumber to run functional tests on our Java8/Spring app. We want our step definition files to remain as DRY as possible and as such plan on using the same step definitions in different feature files. Since we are using a selenium WebDriver
to drive our tests, we need to share the same driver between step definitions.
现在我们正致力于采用 Cucumber 在我们的 Java8/Spring 应用程序上运行功能测试。我们希望我们的步骤定义文件尽可能保持干燥,因此计划在不同的特征文件中使用相同的步骤定义。由于我们使用 seleniumWebDriver
来驱动我们的测试,我们需要在步骤定义之间共享相同的驱动程序。
To demonstrate why having multiple drivers is an issue for us, imagine a feature file that defines two steps: one to navigate to a page, and another to assert that a line appears on that page. If both steps happen to be defined in separate files, the first step definition will use its driver to navigate to the page. By the time the second step definition runs the assertion against its driver it hasn't navigated to the page (since those actions went to the other driver) and the test fails.
为了演示为什么有多个驱动程序对我们来说是一个问题,想象一个定义了两个步骤的功能文件:一个导航到一个页面,另一个断言该页面上出现一行。如果两个步骤碰巧在单独的文件中定义,第一步定义将使用其驱动程序导航到页面。到第二步定义针对其驱动程序运行断言时,它还没有导航到页面(因为这些操作转到了另一个驱动程序)并且测试失败。
We tried implementing a base class (that contains the driver) that each step definition file would extend. As it turns out Cucumber instantiates an instance of each step definition class, and therefore we end up with each step definition having different WebDriver
instances.
我们尝试实现每个步骤定义文件将扩展的基类(包含驱动程序)。事实证明,Cucumber 实例化了每个步骤定义类的实例,因此我们最终使每个步骤定义具有不同的WebDriver
实例。
We thought about using Spring to inject an instance of the WebDriver
in each step definition file, but I believe this would cause the same problem described above.
我们考虑过使用 SpringWebDriver
在每个步骤定义文件中注入 的实例,但我相信这会导致上述相同的问题。
I know that the singleton pattern can be used to achieve this, but ours seems like such a common problem and the singleton pattern feels like overkill. Is this actually the right way to approach it? Or am I missing something really obvious?
我知道可以使用单例模式来实现这一点,但我们的问题似乎很普遍,单例模式感觉有点矫枉过正。这实际上是接近它的正确方法吗?还是我错过了一些非常明显的东西?
Thank you in advance for your help!
预先感谢您的帮助!
回答by troig
I reccomend you to use pico-containeras a dependency injection framework to use with cucumber-jvm
.
我建议您使用pico-container作为依赖注入框架与cucumber-jvm
.
With PicoContainer, you can have a 'base' class with the instance of WebDriver, and then pass this base class automactically to any other class. Or even you could pass directly the web driver if you prefer.
使用 PicoContainer,您可以拥有一个带有 WebDriver 实例的“基”类,然后自动将此基类传递给任何其他类。或者,如果您愿意,甚至可以直接传递网络驱动程序。
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
Example:
例子:
Base class with the instance of WebDriver:
带有 WebDriver 实例的基类:
public class ContextSteps {
private static boolean initialized = false;
private WebDriver driver;
@Before
public void setUp() throws Exception {
if (!initialized) {
// initialize the driver
driver = = new FirefoxDriver();
initialized = true;
}
}
public WebDriver getDriver() {
return driver;
}
}
Other class who access webDriver through pico-container DI.
通过 pico-container DI 访问 webDriver 的其他类。
public class OtherClassSteps {
private ContextSteps contextSteps;
// PicoContainer injects class ContextSteps
public OtherClassSteps (ContextSteps contextSteps) {
this.contextSteps = contextSteps;
}
@Given("^Foo step$")
public void fooStep() throws Throwable {
// Access WebDriver instance
WebDriver driver = contextSteps.getDriver();
}
}
Hope it helps.
希望能帮助到你。
回答by davidicus
This question is old, and I left the project shortly after asking this question, but I went back and looked at the code we put in place (using the singleton pattern) and this is what we ended up with. I forget exactly why we couldn't use pico-container
(it was possibly an organizational constraint) but if you can use extra libraries I remember that solution worked well.
这个问题很老了,我在问这个问题后不久就离开了这个项目,但我回去查看了我们放置的代码(使用单例模式),这就是我们最终得到的。我完全忘记了为什么我们不能使用pico-container
(这可能是组织限制)但是如果您可以使用额外的库,我记得该解决方案运行良好。
I will leave that as the accepted answer but hopefully this solution is useful for those who find themselves in a similar position that I was in a few years ago.
我将把它作为公认的答案,但希望这个解决方案对那些发现自己处于与几年前类似的位置的人有用。
public class TestingBase {
private static TestingBase instance;
private static WebDriver driver;
private static Thread CLOSE_DRIVER = new Thread() {
@Override
public void run() {
driver.close();
}
};
static {
Runtime.getRuntime().addShutdownHook(CLOSE_DRIVER);
}
private TestingBase() {
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setJavascriptEnabled(true);
desiredCapabilities.setCapability("takesScreenshot", false);
desiredCapabilities.setCapability("handlesAlerts", true);
desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, new String[]{
"--web-security=false",
"--ssl-protocol=TLSv1",
"--ignore-ssl-errors=true",
"--webdriver-loglevel=ERROR",
"--webdriver-logfile=/var/log/phantomjs/ghostrdriver.log"
});
desiredCapabilities.setCapability("elementScrollBehavior",true);
driver = new PhantomJSDriver(desiredCapabilities);
}
public static TestingBase getTestingBase() {
if (instance == null) {
instance = new TestingBase();
}
return instance;
}
public static WebDriver getDriver() {
return getTestingBase().driver;
}
}