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 将失败。或者,如果我分别执行每个测试,它们都会通过。

我尝试过的:

关于最后一个要点的非常特别的注释 -- 它神奇地解析了 没有 前缀的模块 -- 所以它不会解析 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 对象!

查看您的代码,但我看不出有任何理由在这里使用数据驱动测试。

  1. 这可以在正常测试中使用一个断言轻松完成
  2. 单元测试最好只测试一件事。但是,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()
    }
}