问题
I have a Spock class, that when run as a test suite, throws 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?
unless I annotate my class with @Stepwise. However, I really don't want the test execution to stop on the first failure, which @Stepwise does.
I've tried writing (copy and pasting) my own extension using this post, but I still get these errors. It is using my extension, as I added some logging statements that were printed out to the console.
Here is one of my modules:
class IconRow extends Module {
static content = {
iconRow (required: false) {$("div.report-toolbar")}
}
}
And a page that uses it:
class Report extends SomeOtherPage {
static at = {$("div.grid-container").displayed}
static content = {
iconRow { module IconRow }
}
}
And a snippet of the test that is failing:
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()
}
}
When executed as a suite I work
passes and I don't work
fails because it cannot identify "iconRow" as content for the page. If I switch the order of the test cases, I don't work
will pass and I work
will fail. Alternatively, if I execute each test separately, they both pass.
What I have tried:
- Adding/removing the
required: true
property from content in the modules - Prefixing the module name with the class, such as
IconRow.iconRow
- Defining my modules as static
@Shared
properties - Initialize the modules both in and outside of my
setupSpec()
- Making simple getter methods in each module's class that return the module, and referencing content such as
IconRow.getIconRow().columnHeaders*.attr("innerText")*.toUpperCase()
- Moving the contents of my
setupSpec()
intosetup()
- Adding
autoClearCookies = false
into my GebConfig.groovy - Making a
@Shared Report report
variable and prefix all modules with that such asreport.iconRow
Very peculiar note about that last bullet point -- it magically resolves the modules that don't have the prefix -- so it won't resolve report.IconRow
but will resolve just iconRow
-- absolutely bizarre, because if I remove that variable the module that was just previously working suddenly can't be resolved again. I even tried declaring this variable and then not prefixing anything, and that did not work either.
Another problem that I keep banging my head against the wall with is that I'm also not sure of where the problem is. The error it throws leads me to believe that it's a project setup issue, but running each feature individually works fine, so it appears to be resolving the classes just fine.
On the other hand, perhaps it's an issue with the session and/or cookies? Although I have yet to see any official documentation on this, it seems to be the general consensus (from other posts and articles I've read) that only using @Stepwise
will maintain your session between feature methods. If this is the case, why is my extension not working? It's pretty much a copy and paste of @Stepwise
without the skipFeaturesAfterFirstFailingFeature
method (I can post if needed), unless there is some other stuff going on behind the scenes with @Stepwise
.
Apologies for the wall of text, but I've been trying to figure this out for about 6 hours now, so my brain is pretty fried.
回答1:
Geb has special support for @Stepwise
, if a spec is annotated with it it does not call resetBrowser()
after each test, instead it is called after the spec is completed. See the code on github
So basically you need to change your setupSpec
to setup
so that it will be executed before each test.
Regarding your observation, if you just run a focused test the setupSpec
is executed for that test and thus it passes. The problem arises, that the cleanup is invoked afterwards and resets the browser, breaking subsequent tests.
EDIT
I overlooked your usage of where
blocks, everything in the where block needs to be statically (@Shared
) available, so using instance level constructs won't work. Resetting the browser will also kill every reference so just getting it before wont work either. Basically, don't use Geb objects in where
blocks!
Looking at your code however I don't see any reason to use data driven tests here.
- This can be easily done with one assertion in a normal test
- It is good practice for unit tests to just test one thing. Geb however, is not an unit test but an acceptance/frontend test. The problem here is that they are way slower than unit tests and it makes sense to combine sensible assertions into one test.
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()
}
}
来源:https://stackoverflow.com/questions/46435166/class-cannot-resolve-module-as-content-unless-stepwise-used