目前我们正在努力采用Cucumber在我们的Java8 / Spring应用程序上运行功能测试。我们希望我们的步骤定义文件尽可能保持DRY,因此计划在不同的功能文件中使用相同的步骤定义。由于我们使用selenium WebDriver
来驱动我们的测试,我们需要在步骤定义之间共享相同的驱动程序。
为了说明为什么让多个驱动程序对我们来说是一个问题,想象一下定义两个步骤的功能文件:一个用于导航到一个页面,另一个用于断言该页面上出现一行。如果两个步骤碰巧在单独的文件中定义,则第一步定义将使用其驱动程序导航到该页面。当第二步定义运行针对其驱动程序的断言时,它还没有导航到页面(因为这些操作转到了另一个驱动程序)并且测试失败。
我们尝试实现每个步骤定义文件将扩展的基类(包含驱动程序)。事实证明,Cucumber实例化了每个步骤定义类的实例,因此我们最终得到的每个步骤定义都有不同的WebDriver
个实例。
我们考虑过使用Spring在每个步骤定义文件中注入WebDriver
的实例,但我相信这会导致上述相同的问题。
我知道单身模式可以用来实现这一目标,但是我们的模式看起来像是一个常见的问题而单身模式就像是矫枉过正。这实际上是接近它的正确方法吗?或者我错过了一些非常明显的东西?
提前感谢您的帮助!
答案 0 :(得分:7)
我建议您使用pico-container作为依赖注入框架与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-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();
}
}
希望它有所帮助。
答案 1 :(得分:2)
这个问题已经过时了,我在问这个问题之后不久就离开了这个项目,但我回过头来看看我们放置的代码(使用单例模式),这就是我们最终得到的结果。我忘记了为什么我们不能使用pico-container
(这可能是一个组织约束),但如果你可以使用额外的库我记得解决方案运行良好。
我会把它作为公认的答案,但希望这个解决方案对那些发现自己处于几年前我所处位置的人有用。
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;
}
}