Class 无法将模块解析为内容,除非使用 @Stepwise
Class cannot resolve module as content unless @Stepwise used
我有一个 Spock class,当 运行 作为测试套件时,抛出 Unable to resolve iconRow as content for geb.Page, or as a property on its Navigator context. Is iconRow a class you forgot to import?
除非我用 @Stepwise 注释我的 class。但是,我真的不希望测试执行在第一次失败时停止,@Stepwise 确实如此。
我尝试使用 post 编写(复制和粘贴)我自己的扩展程序,但我仍然遇到这些错误。它正在使用我的扩展程序,因为我添加了一些打印到控制台的日志记录语句。
这是我的模块之一:
class IconRow extends Module {
static content = {
iconRow (required: false) {$("div.report-toolbar")}
}
}
以及使用它的页面:
class Report extends SomeOtherPage {
static at = {$("div.grid-container").displayed}
static content = {
iconRow { module IconRow }
}
}
以及失败的测试片段:
class MyFailingTest extends GebReportingSpec {
def setupSpec() {
via Dashboard
SomeClass.login("SourMonk", "myPassword")
assert page instanceof Dashboard
nav.goToReport("Some report name")
assert page instanceof Report
}
@Unroll
def "I work"() {
given:
at Report
expect:
this == that
where:
this << ["some list", "of values"]
that << anotherModule.someContent*.@id
}
@Unroll
def "I don't work"() {
given:
at Report
expect:
this == that
where:
this << ["some other", "list", "of values"]
that << iconRow.columnHeaders*.attr("innerText")*.toUpperCase()
}
}
作为套件执行时 I work
通过,而 I don't work
失败,因为它无法将 "iconRow" 识别为页面内容。如果我调换测试用例的顺序,I don't work
将通过,而 I work
将失败。或者,如果我分别执行每个测试,它们都会通过。
我尝试过的:
- Adding/removing 来自模块内容的
required: true
属性
- 在模块名称前加上class,例如
IconRow.iconRow
- 将我的模块定义为静态
@Shared
属性
- 初始化我
setupSpec()
内部和外部的模块
- 在return模块的每个模块class中制作简单的getter方法,并引用
IconRow.getIconRow().columnHeaders*.attr("innerText")*.toUpperCase()
等内容
- 将我的
setupSpec()
的内容移动到 setup()
- 将
autoClearCookies = false
添加到我的 GebConfig.groovy
- 创建一个
@Shared Report report
变量并在所有模块前添加前缀,例如 report.iconRow
关于最后一个要点的非常特别的注释 -- 它神奇地解析了 没有 前缀的模块 -- 所以它不会解析 report.IconRow
但只会解析 iconRow
—— 绝对奇怪,因为如果我删除该变量,之前刚刚工作的模块突然无法再次解析。我什至尝试声明这个变量,然后不添加任何前缀,但这也没有用。
另一个让我一直苦苦思索的问题是,我也不确定问题出在哪里。它抛出的错误让我相信这是一个项目设置问题,但 运行 每个功能单独工作正常,所以它似乎很好地解决了 classes。
另一方面,这可能是会话 and/or cookie 的问题?尽管我还没有看到任何关于此的官方文档,但似乎普遍认为(来自其他 post 和我读过的文章)仅使用 @Stepwise
将维持您在特征方法之间的会话.如果是这样,为什么我的扩展程序不起作用?它几乎是 @Stepwise
的复制和粘贴,没有 skipFeaturesAfterFirstFailingFeature
方法(如果需要,我可以 post),除非 @Stepwise
在幕后发生了一些其他事情.
抱歉文字墙,但我已经尝试解决这个问题大约 6 个小时了,所以我的大脑很炸。
Geb 对 @Stepwise
有特别的支持,如果用它注释规范,它不会在每次测试后调用 resetBrowser()
,而是在规范完成后调用。请参阅 github
上的代码
所以基本上您需要将 setupSpec
更改为 setup
以便它在每次测试之前执行。
根据您的观察,如果您只是 运行 一个重点测试,则针对该测试执行 setupSpec
并因此通过。问题出现了,之后调用清理并重置浏览器,破坏后续测试。
编辑
我忽略了您对 where
块的使用,where 块中的所有内容都需要静态 (@Shared
) 可用,因此使用实例级构造将不起作用。重置浏览器也会杀死所有引用,所以在不起作用之前获取它。基本上,不要在 where
块中使用 Geb 对象!
查看您的代码,但我看不出有任何理由在这里使用数据驱动测试。
- 这可以在正常测试中使用一个断言轻松完成
- 单元测试最好只测试一件事。但是,Geb 不是单元测试,而是 acceptance/frontend 测试。这里的问题是它们比单元测试慢得多,将合理的断言组合到一个测试中是有意义的。
class MyFailingTest extends GebReportingSpec {
def setup() {
via Dashboard
SomeClass.login("SourMonk", "myPassword")
assert page instanceof Dashboard
nav.goToReport("Some report name")
assert page instanceof Report
}
def "I work"() {
given:
at Report
expect:
["some list", "of values"] == anotherModule.someContent*.@id
}
def "I don't work"() {
given:
at Report
expect:
["some other", "list", "of values"] == iconRow.columnHeaders*.attr("innerText")*.toUpperCase()
}
}
我有一个 Spock class,当 运行 作为测试套件时,抛出 Unable to resolve iconRow as content for geb.Page, or as a property on its Navigator context. Is iconRow a class you forgot to import?
除非我用 @Stepwise 注释我的 class。但是,我真的不希望测试执行在第一次失败时停止,@Stepwise 确实如此。
我尝试使用
这是我的模块之一:
class IconRow extends Module {
static content = {
iconRow (required: false) {$("div.report-toolbar")}
}
}
以及使用它的页面:
class Report extends SomeOtherPage {
static at = {$("div.grid-container").displayed}
static content = {
iconRow { module IconRow }
}
}
以及失败的测试片段:
class MyFailingTest extends GebReportingSpec {
def setupSpec() {
via Dashboard
SomeClass.login("SourMonk", "myPassword")
assert page instanceof Dashboard
nav.goToReport("Some report name")
assert page instanceof Report
}
@Unroll
def "I work"() {
given:
at Report
expect:
this == that
where:
this << ["some list", "of values"]
that << anotherModule.someContent*.@id
}
@Unroll
def "I don't work"() {
given:
at Report
expect:
this == that
where:
this << ["some other", "list", "of values"]
that << iconRow.columnHeaders*.attr("innerText")*.toUpperCase()
}
}
作为套件执行时 I work
通过,而 I don't work
失败,因为它无法将 "iconRow" 识别为页面内容。如果我调换测试用例的顺序,I don't work
将通过,而 I work
将失败。或者,如果我分别执行每个测试,它们都会通过。
我尝试过的:
- Adding/removing 来自模块内容的
required: true
属性 - 在模块名称前加上class,例如
IconRow.iconRow
- 将我的模块定义为静态
@Shared
属性 - 初始化我
setupSpec()
内部和外部的模块
- 在return模块的每个模块class中制作简单的getter方法,并引用
IconRow.getIconRow().columnHeaders*.attr("innerText")*.toUpperCase()
等内容
- 将我的
setupSpec()
的内容移动到setup()
- 将
autoClearCookies = false
添加到我的 GebConfig.groovy - 创建一个
@Shared Report report
变量并在所有模块前添加前缀,例如report.iconRow
关于最后一个要点的非常特别的注释 -- 它神奇地解析了 没有 前缀的模块 -- 所以它不会解析 report.IconRow
但只会解析 iconRow
—— 绝对奇怪,因为如果我删除该变量,之前刚刚工作的模块突然无法再次解析。我什至尝试声明这个变量,然后不添加任何前缀,但这也没有用。
另一个让我一直苦苦思索的问题是,我也不确定问题出在哪里。它抛出的错误让我相信这是一个项目设置问题,但 运行 每个功能单独工作正常,所以它似乎很好地解决了 classes。
另一方面,这可能是会话 and/or cookie 的问题?尽管我还没有看到任何关于此的官方文档,但似乎普遍认为(来自其他 post 和我读过的文章)仅使用 @Stepwise
将维持您在特征方法之间的会话.如果是这样,为什么我的扩展程序不起作用?它几乎是 @Stepwise
的复制和粘贴,没有 skipFeaturesAfterFirstFailingFeature
方法(如果需要,我可以 post),除非 @Stepwise
在幕后发生了一些其他事情.
抱歉文字墙,但我已经尝试解决这个问题大约 6 个小时了,所以我的大脑很炸。
Geb 对 @Stepwise
有特别的支持,如果用它注释规范,它不会在每次测试后调用 resetBrowser()
,而是在规范完成后调用。请参阅 github
所以基本上您需要将 setupSpec
更改为 setup
以便它在每次测试之前执行。
根据您的观察,如果您只是 运行 一个重点测试,则针对该测试执行 setupSpec
并因此通过。问题出现了,之后调用清理并重置浏览器,破坏后续测试。
编辑
我忽略了您对 where
块的使用,where 块中的所有内容都需要静态 (@Shared
) 可用,因此使用实例级构造将不起作用。重置浏览器也会杀死所有引用,所以在不起作用之前获取它。基本上,不要在 where
块中使用 Geb 对象!
查看您的代码,但我看不出有任何理由在这里使用数据驱动测试。
- 这可以在正常测试中使用一个断言轻松完成
- 单元测试最好只测试一件事。但是,Geb 不是单元测试,而是 acceptance/frontend 测试。这里的问题是它们比单元测试慢得多,将合理的断言组合到一个测试中是有意义的。
class MyFailingTest extends GebReportingSpec {
def setup() {
via Dashboard
SomeClass.login("SourMonk", "myPassword")
assert page instanceof Dashboard
nav.goToReport("Some report name")
assert page instanceof Report
}
def "I work"() {
given:
at Report
expect:
["some list", "of values"] == anotherModule.someContent*.@id
}
def "I don't work"() {
given:
at Report
expect:
["some other", "list", "of values"] == iconRow.columnHeaders*.attr("innerText")*.toUpperCase()
}
}