Groovy Geb&x2B;Spock测试可以';t重复使用内容c';tors,失败并出现MissingMethodException
我最近才开始为我们的web应用程序创建Geb/Spock测试,考虑到我对Geb、Spock和Groovy的知识有限,我遇到了一个毫无意义的错误(考虑到我的Java经验) 因此,这里是有问题的模块:Groovy Geb&x2B;Spock测试可以';t重复使用内容c';tors,失败并出现MissingMethodException,groovy,spock,geb,Groovy,Spock,Geb,我最近才开始为我们的web应用程序创建Geb/Spock测试,考虑到我对Geb、Spock和Groovy的知识有限,我遇到了一个毫无意义的错误(考虑到我的Java经验) 因此,这里是有问题的模块: import geb.Module import geb.navigator.Navigator class Tile extends Module { def currencyPair static content = { amount {
import geb.Module
import geb.navigator.Navigator
class Tile extends Module {
def currencyPair
static content = {
amount {
$(".currencypair-span", text: containsWord(currencyPair))
.parent().parent()
.find(".tile-amount-setup").find("input") }
}
}
没什么特别的
以下是页面(但我不确定这一切是如何结合在一起的):
以下是测试规范:
import geb.spock.GebSpec
import spock.lang.*
import org.openqa.selenium.Keys
class BugSpec extends SbkSpec {
final CURPAIR = "FOOBAR"
def setupSpec() {
accountSelector.dropDown.click()
accountSelector.dropDown << Keys.chord(Keys.CONTROL, "a")
accountSelector.dropDown << "FxOnly"
accountSelector.dropDown << Keys.ENTER
waitFor() { accountSelector.dropDown.value() == "FXOnly" }
tileLayout("Majors").tab.click()
}
def "test1"() {
given:
tile(CURPAIR).amount.click()
when:
println("foo")
then:
waitFor {true}
}
def "test2"() {
given:
tile(CURPAIR).amount.click()
when: println("bar")
then:
waitFor {true}
}
}
使用内置的base
GebSpec
/GebReportingSpec
Geb会将缺少的方法调用发送到spec的浏览器属性的页面属性。在第一次测试之前,有些东西(如果没有看到更多的代码,就不可能说出它到底是什么)将该属性设置为TraderApp
的一个实例。Geb在每个测试之间重新创建浏览器
实例,这意味着页面实例被重置为默认值,即页面
的实例。如果将页面设置为TraderApp
的实例,则将找到tile()
方法:
def "test2"() {
given:
page TraderApp
tile(CURPAIR).amount.click()
when: println("bar")
then:
waitFor {true}
}
如果您为BugSpec
的所有超类链提供代码,直到扩展GebSpec
/GebReportingSpec
的超类链,那么就更容易推理和帮助。在我看来,您可能正在处理一种气味,即测试的设置方式与执行顺序有关。文档中没有这样的方法:。你为什么声称它正在“消失”?tail
方法调用被重定向到此接口的实例:通过此类:请再次阅读问题@Opal。第一次调用tile()
成功,第一次测试通过(注意TESTS
输出中打印的“foo
”),但第二次调用相同方法失败,引发异常。一个调用如何工作,但对同一方法的第二个调用却声称该方法不存在?是的,的确如此。有趣。是否有复制的机会?很难说,因为缺少基类等,但很可能是设置不正确,并且TraderApp
不是第二次测试开始时的当前页面(setupSpec
只会在第一次测试之前运行)。@Peter,我应该在问题中提供哪些其他类?我对Geb非常模糊,目前对Groovy更加困惑,因此我没有正确的心智模型来理解所有的类和方法调用是如何适应的。嗨,@Erdi。非常感谢您的反馈。我已经更新了问题,添加了BugSpec超类的代码。:-)此外,建议的修复(添加页面TraderApp
行)似乎没有修复该问题。我希望额外的代码会有帮助。啊,我撒谎了。这个把戏玩得很好!我不得不在所有测试中添加这一行,以及BugSpec
的setupSpec
方法:-我会接受你的回答,但希望你能帮我们找出超类(代码气味)中的问题,好吗?我不认为那里有任何代码气味。setupSpec()
s中的所有代码实际上都应该在setup()
方法中。这是因为浏览器状态在测试方法之间重置,并且所有cookie都将从中删除。这就是为什么您总是希望登录并显式转到页面,而不是期望在上一次测试后处于任何特定状态的浏览器。有些人认为这是过分的,并试图管理浏览器状态,但这本质上导致了相互依赖和脆弱的测试。我个人认为,你应该从一个干净的状态开始每项测试。非常感谢你的启发性评论,@Erdi。作为一个涉猎Haskell函数编程的人,我很欣赏你关于避免在测试之间保持太多状态的评论。但遗憾的是,这会使测试套件运行变慢。但我现在对Geb如何做以及如何解决这个问题有了更好的想法;非常感谢-DIf如果您确实需要按顺序运行测试,您可以将@Stepwise注释添加到规范顶部。这将导致按定义的顺序执行功能,并且Geb不会在每次测试之间重置浏览器。
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running BugSpec
Starting ChromeDriver (v2.10.267521) on port 32075
Only local connections are allowed.
foo
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 19.425 sec <<< FAILURE!
test2(BugSpec) Time elapsed: 0.175 sec <<< ERROR!
groovy.lang.MissingMethodException: No signature of method: geb.navigator.NonEmptyNavigator.tile() is applicable for argument types: (java.lang.String) values: [FOOBAR]
Possible solutions: size(), tail(), filter(java.lang.String), find(java.lang.String), is(java.lang.String), take(int)
at geb.navigator.NonEmptyNavigator.methodMissing(NonEmptyNavigator.groovy:463)
at geb.content.NavigableSupport.methodMissing(NavigableSupport.groovy:123)
at geb.Browser.methodMissing(Browser.groovy:194)
at geb.spock.GebSpec.methodMissing(GebSpec.groovy:51)
at BugSpec.test2(BugSpec.groovy:35)
import geb.spock.GebReportingSpec
class SbkSpec extends GebReportingSpec {
def setupSpec() {
def environment = System.getProperty("geb.env");
given:
to AuthApp
expect:
at AuthApp
when:
def username = browser.getConfig().getRawConfig().get("username")
def password = browser.getConfig().getRawConfig().get("password")
login.username.value(username)
login.password.value(password)
login.loginButton.click()
then:
at TraderApp
and:
waitFor() { accountSelector.dropDown.value() == "FOOBAR-ACCOUNT" }
}
def cleanupSpec() {
given:
at TraderApp
then:
logout.logoutButton.click()
}
}
def "test2"() {
given:
page TraderApp
tile(CURPAIR).amount.click()
when: println("bar")
then:
waitFor {true}
}