/doc/manual/src/docs/asciidoc/110-testing.adoc
AsciiDoc | 189 lines | 131 code | 58 blank | 0 comment | 0 complexity | a4a40e654ca510d32660d1199cdcf122 MD5 | raw file
Possible License(s): Apache-2.0
- [[testing]]
- = Testing
- Geb provides first class support for functional web testing via integration with popular testing frameworks such as {spock}, {junit}, {testng} and {cucumber-jvm}.
- [[spock-junit-testng]]
- == Spock, JUnit & TestNG
- The Spock, JUnit and TestNG integrations work fundamentally the same way.
- They provide superclasses that setup a `{browser-api}` instance that all method calls and property accesses/references resolve against via Groovy's `methodMissing` and `propertyMissing` mechanism.
- These superclasses are just a thin layer on top of `{geb-test-manager-api}` and utilize an AST transformation registered using `{dynamically-dispatches-to-browser-api}` annotation to implement dynamic method and property dispatching onto the instance of `{browser-api}`.
- If the provided superclasses are inconvenient to use, or you wish to use a testing framework for which an integration is not provided out of the box then it's highly recommended to use `{geb-test-manager-api}` together with `{dynamically-dispatches-to-browser-api}` when implementing your custom integration.
- Taking a look at the code of the superclasses providing the built-in support for test frameworks is a good starting point when undertaking implementation of a custom integration.
- [TIP]
- ====
- Recall that the browser instance also forwards any method calls or property accesses/references that it can't handle to its current page object, which helps to remove a lot of noise from the test.
- ====
- Consider the following Spock spec…
- [source,groovy]
- ----
- include::{snippets-dir}/testing/FunctionalSpec.groovy[tag=concise,indent=0]
- ----
- Which is equivalent to…
- [source,groovy]
- ----
- include::{snippets-dir}/testing/FunctionalSpec.groovy[tag=verbose,indent=0]
- ----
- === Configuration
- The browser instance is created by the testing integrations via use of `{geb-test-manager-api}`. The <<configuration, configuration mechanism>> allows you to control aspects such as the driver implementation and base URL.
- [[testing-reporting]]
- === Reporting
- The Spock, JUnit and TestNG integrations also ship a superclass (the name of the class for each integration module is provided below) that automatically takes reports with the label “failure” if a test fails.
- They also set the <<report-group, report group>> to the name of the test class (substituting “.” with “/”).
- The `{browser-report-method-api}` browser method is replaced with a specialised version.
- This method works the same as the browser method, but adds counters and the current test method name as prefixes to the given label.
- [source,groovy]
- ----
- include::{snippets-dir}/testing/ReportingFunctionalSpec.groovy[tag=example,indent=0]
- ----
- <1> Take a report of the login screen.
- Assuming a configured `reportsDir` of `reports/geb` and the default reporters (i.e. `{screenshot-reporter-api}` and `{page-source-reporter-api}`), we would find the following files:
- * `reports/geb/my/tests/LoginSpec/001-001-login-login screen.html`
- * `reports/geb/my/tests/LoginSpec/001-001-login-login screen.png`
- If the assertion on the title fails then the following files would be generated as well:
- * `reports/geb/my/tests/LoginSpec/001-002-login-failure.html`
- * `reports/geb/my/tests/LoginSpec/001-002-login-failure.png`
- The report file name format is:
- ----
- «test method number»-«report number in test method»-«test method name»-«label».«extension»
- ----
- Reporting is an extremely useful feature and can help you diagnose test failures much easier.
- Wherever possible, favour the use of the auto-reporting base classes.
- [[cookie-management-in-tests]]
- === Cookie management
- `{geb-test-manager-api}` and thus also the Spock, JUnit and TestNG built-in integrations will automatically clear the browser's cookies for the current domain at the end of each test method.
- This happens when `GebTestManager.afterTest()` is called unless `GebTestManager.resetBrowserAfterEachTestPredicate` evaluates to `false` like it does for `@Stepwise` Spock specifications - in such case cookie clearing happens in `GebTestManager.afterTestClass()` (meaning that all feature methods in a stepwise spec share the same browser state).
- This auto-clearing of cookies can be <<auto-clearing-cookies-configuration, disabled via configuration>>.
- If you need to clear cookies in multiple domains you will need to manually track the urls and call `{browser-clear-cookies-urls-api}`.
- [[web-storage-management-in-tests]]
- === Web storage management
- `{geb-test-manager-api}` and thus also the Spock, JUnit and TestNG built-in integrations can be <<auto-clearing-web-storage-configuration, configured>> to automatically clear the browser's web storage, that is both local and session storage, for the current domain at the end of each test method.
- This happens when `GebTestManager.afterTest()` is called unless `GebTestManager.resetBrowserAfterEachTestPredicate` evaluates to `false` like it does for `@Stepwise` Spock specifications - in such case cookie clearing happens in `GebTestManager.afterTestClass()` (meaning that all feature methods in a stepwise spec share the same browser state).
- === Restarting the browser mid-test
- Should you ever wish to restart the browser mid-test you have to be aware that there are two layers of caching of the driver instance within Geb's testing support.
- Firstly the lazy initialised `Browser` instance stored as a field in the `{geb-test-manager-api}` instance held by base classes providing support for various test frameworks holds a reference to a `WebDriver` instance - you will therefore need to call `resetBrowser()` method from the base class or directly on the `{geb-test-manager-api}` instance to clear that field.
- Secondly, Geb caches `WebDriver` instances by default as described in the section about <<implicit-driver-lifecycle, implicit driver lifecycle>>. To clear the cache and quit the browser you will need to call `{clear-browser-cache-and-quit-api}`.
- Therefore, you can use the following code within a test to restart the browser:
- [source,groovy]
- ----
- include::{snippets-dir}/testing/BrowserRestartSpec.groovy[tag=restart,indent=0]
- ----
- === JAR and class names
- The following table illustrates the specific JARs and class names for various test frameworks that Geb integrates with.
- |===
- |Framework |JAR |Base Class |Reporting Base Class
- |Spock |http://mvnrepository.com/artifact/{geb-group}/geb-spock[geb-spock] |link:api/geb/spock/GebSpec.html[`geb.spock.GebSpec`] |link:api/geb/spock/GebReportingSpec.html[`geb.spock.GebReportingSpec`]
- |JUnit 4 |http://mvnrepository.com/artifact/{geb-group}/geb-junit4[geb-junit4] |link:api/geb/junit4/GebTest.html[`geb.junit4.GebTest`] |link:api/geb/junit4/GebReportingTest.html[`geb.junit4.GebReportingTest`]
- |JUnit 5 |http://mvnrepository.com/artifact/{geb-group}/geb-junit5[geb-junit5] |link:api/geb/junit5/GebTest.html[`geb.junit5.GebTest`] |link:api/geb/junit5/GebReportingTest.html[`geb.junit5.GebReportingTest`]
- |TestNG |http://mvnrepository.com/artifact/{geb-group}/geb-testng[geb-testng] |link:api/geb/testng/GebTest.html[`geb.testng.GebTest`] |link:api/geb/testng/GebReportingTest.html[`geb.testng.GebReportingTest`]
- |===
- === Example projects
- The following projects can be used as starting references:
- * link:https://github.com/geb/geb-example-gradle[geb-example-gradle]
- [[cucumber-jvm]]
- == Cucumber (Cucumber-JVM)
- It is possible to both:
- * Write your own {cucumber-jvm} steps that manipulate Geb
- * Use a library of pre-built steps that drives Geb to do many common tasks
- === Writing your own steps
- Use Geb's <<binding, binding management features>> to bind a browser in before / after hooks, often in a file named `env.groovy`:
- [source,groovy]
- ----
- def bindingUpdater
- Before() { scenario ->
- bindingUpdater = new BindingUpdater(binding, new Browser())
- bindingUpdater.initialize()
- }
- After() { scenario ->
- bindingUpdater.remove()
- }
- ----
- Then normal Geb commands and objects are available in your Cucumber steps:
- [source,groovy]
- ----
- import static cucumber.api.groovy.EN.*
- Given(~/I am on the DuckDuckGo search page/) { ->
- to DuckDuckGoHomePage
- waitFor { at(DuckDuckGoHomePage) }
- }
- When(~/I search for "(.*)"/) { String query ->
- page.search.value(query)
- page.searchButton.click()
- }
- Then(~/I can see some results/) { ->
- assert at(DuckDuckGoResultsPage)
- }
- Then(~/the first link should be "(.*)"/) { String text ->
- waitFor { page.results }
- assert page.resultLink(0).text()?.contains(text)
- }
- ----
- === Using pre-built steps
- The {geb-cucumber} project has a set of pre-built cucumber steps that drive Geb. So for example a feature with steps similar to the above would look like:
- ----
- When I go to the duck duck go home page
- And I enter "cucumber-jvm github" into the search field
- And I click the search button
- Then the results table 1st row link matches /cucumber\/cucumber-jvm · GitHub.*/
- ----
- See {geb-cucumber} for more examples.
- geb-cucumber also does Geb binding automatically, so if it is picked up you don't need to do it yourself as above.
- === Example project
- The following project has examples of both writing your own steps and using geb-cucumber:
- * link:https://github.com/geb/geb-example-cucumber-jvm[geb-example-cucumber-jvm]