现在我们正在努力采用Cucumber在我们的Java8/Spring应用程序上运行功能测试。我们希望我们的步骤定义文件尽可能保持干燥,因此计划在不同的功能文件中使用相同的步骤定义。由于我们使用seleniumWebDriver
来驱动我们的测试,我们需要在步骤定义之间共享相同的驱动程序。
为了说明为什么拥有多个驱动程序对我们来说是一个问题,想象一个定义了两个步骤的功能文件:一个是导航到一个页面,另一个是断言该页面上出现了一行。如果这两个步骤碰巧在单独的文件中定义,第一步定义将使用其驱动程序导航到该页面。当第二步定义针对其驱动程序运行断言时,它还没有导航到该页面(因为这些操作进入了另一个驱动程序),测试失败。
我们尝试实现一个基类(包含驱动程序),每个步骤定义文件都将扩展。事实证明,Cucumber实例化了每个步骤定义类的一个实例,因此我们最终得到每个步骤定义都有不同的WebDriver
实例。
我们考虑过使用Spring在每个步骤定义文件中注入一个WebDriver
的实例,但我相信这会导致上述相同的问题。
我知道单例模式可以用来实现这一点,但是我们的模式似乎是一个常见的问题,单例模式感觉像是矫枉过正。这实际上是正确的方法吗?还是我错过了一些非常明显的东西?
提前感谢您的帮助!
我建议您使用Pico容器作为依赖注入框架,与cucumber-jvm
一起使用。
使用PicoContainer,您可以拥有一个带有WebDriver实例的“基类”,然后将此基类自动传递给任何其他类。或者,如果您愿意,甚至可以直接传递Web驱动程序。
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
示例:
带有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;
}
}
通过Pico容器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();
}
}
希望有帮助。
这个问题很老,我在问了这个问题后不久就离开了项目,但是我回去看了看我们放置的代码(使用单例模式),这就是我们最终得到的。我忘记了为什么我们不能使用Pico-容器
(这可能是一个组织约束),但是如果你可以使用额外的库,我记得那个解决方案运行良好。
我将把它作为公认的答案,但希望这个解决方案对那些发现自己处于与几年前相似位置的人有用。
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;
}
}