# Testing Guide

version 5.1.0

## 1. Introduction

The Groovy programming language comes with great support for writing tests. In addition to the language features and test integration with state-of-the-art testing libraries and frameworks, the Groovy ecosystem has born a rich set of testing libraries and frameworks.

This chapter will start with language specific testing features and continue with a closer look at JUnit integration, Spock for specifications, and Geb for functional tests. Finally, we’ll do an overview of other testing libraries known to be working with Groovy.

## 2. Language Features

Besides integrated support for JUnit, the Groovy programming language comes with features that have proven to be very valuable for test-driven development. This section gives insight on them.

### 2.1. Power Assertions

Writing tests means formulating assumptions by using assertions. In Java this can be done by using the `assert` keyword that has been added in J2SE 1.4. In Java, `assert` statements can be enabled via the JVM parameters `-ea` (or `-enableassertions`) and `-da` (or `-disableassertions`). Assertion statements in Java are disabled by default.

Groovy comes with a rather powerful variant of `assert` also known as power assertion statement. Groovy’s power `assert` differs from the Java version in its output given the boolean expression validates to `false`:

    def x = 1
    assert x == 2

    // Output:             (1)
    //
    // Assertion failed:
    // assert x == 2
    //        | |
    //        1 false

1 | This section shows the std-err output

The `java.lang.AssertionError` that is thrown whenever the assertion can not be validated successfully, contains an extended version of the original exception message. The power assertion output shows evaluation results from the outer to the inner expression.

The power assertion statements true power unleashes in complex Boolean statements, or statements with collections or other `toString`-enabled classes:

    def x = [1,2,3,4,5]
    assert (x << 6) == [6,7,8,9,10]

    // Output:
    //
    // Assertion failed:
    // assert (x << 6) == [6,7,8,9,10]
    //         | |     |
    //         | |     false
    //         | [1, 2, 3, 4, 5, 6]
    //         [1, 2, 3, 4, 5, 6]

Another important difference from Java is that in Groovy assertions are enabled by default. It has been a language design decision to remove the possibility to deactivate assertions. Or, as Bertrand Meyer stated, `it makes no sense to take off your swim ring if you put your feet into real water`.

One thing to be aware of are methods with side effects inside Boolean expressions in power assertion statements. As the internal error message construction mechanism does only store references to instances under target, it happens that the error message text is invalid at rendering time in case of side-effecting methods involved:

    assert [[1,2,3,3,3,3,4]].first().unique() == [1,2,3]

    // Output:
    //
    // Assertion failed:
    // assert [[1,2,3,3,3,3,4]].first().unique() == [1,2,3]
    //                          |       |        |
    //                          |       |        false
    //                          |       [1, 2, 3, 4]
    //                          [1, 2, 3, 4]           (1)

1 | The error message shows the actual state of the collection, not the state before the `unique` method was applied

| If you choose to provide a custom assertion error message this can be done by using the Java syntax `assert expression1 : expression2` where `expression1` is the Boolean expression and `expression2` is the custom error message. Be aware though that this will disable the power assert and will fully fall back to custom error messages on assertion errors.

### 2.2. Mocking and Stubbing

Groovy has excellent built-in support for a range of mocking and stubbing alternatives. When using Java, dynamic mocking frameworks are very popular. A key reason for this is that it is hard work creating custom hand-crafted mocks using Java. Such frameworks can be used easily with Groovy if you choose but creating custom mocks is much easier in Groovy. You can often get away with simple maps or closures to build your custom mocks.

The following sections show ways to create mocks and stubs with Groovy language features only.

#### 2.2.1. Map Coercion

By using maps or expandos, we can incorporate desired behaviour of a collaborator very easily as shown here:

    class TranslationService {
        String convert(String key) {
            return "test"
        }
    }

    def service = [convert: { String key -> 'some text' }] as TranslationService
    assert 'some text' == service.convert('key.text')

The `as` operator can be used to coerce a map to a particular class. The given map keys are interpreted as method names and the values, being `groovy.lang.Closure` blocks, are interpreted as method code blocks.

| Be aware that map coercion can get into the way if you deal with custom `java.util.Map` descendant classes in combination with the `as` operator. The map coercion mechanism is targeted directly at certain collection classes, it doesn’t take custom classes into account.

#### 2.2.2. Closure Coercion

The 'as' operator can be used with closures in a neat way which is great for developer testing in simple scenarios. We haven’t found this technique to be so powerful that we want to do away with dynamic mocking, but it can be very useful in simple cases none-the-less.

Classes or interfaces holding a single method, including SAM (single abstract method) classes, can be used to coerce a closure block to be an object of the given type. Be aware that for doing this, Groovy internally create a proxy object descending for the given class. So the object will not be a direct instance of the given class. This important if, for example, the generated proxy object’s metaclass is altered afterwards.

Let’s have an example on coercing a closure to be of a specific type:

    def service = { String key -> 'some text' } as TranslationService
    assert 'some text' == service.convert('key.text')

Groovy supports a feature called implicit SAM coercion. This means that the `as` operator is not necessary in situations where the runtime can infer the target SAM type. This type of coercion might be useful in tests to mock entire SAM classes:

    abstract class BaseService {
        abstract void doSomething()
    }

    BaseService service = { -> println 'doing something' }
    service.doSomething()

#### 2.2.3. MockFor and StubFor

The Groovy mocking and stubbing classes can be found in the `groovy.mock.interceptor` package.

The `MockFor` class supports (typically unit) testing of classes in isolation by allowing a strictly ordered expectation of the behavior of collaborators to be defined. A typical test scenario involves a class under test and one or more collaborators. In such a scenario it is often desirable to just test the business logic of the class under test. One strategy for doing that is to replace the collaborator instances with simplified mock objects to help isolate out the logic in the test target. MockFor allows such mocks to be created using meta-programming. The desired behavior of collaborators is defined as a behavior specification. The behavior is enforced and checked automatically.

Let’s assume our target classes looked like this:

    class Person {
        String first, last
    }

    class Family {
        Person father, mother
        def nameOfMother() { "$mother.first $mother.last" }
    }

With `MockFor`, a mock expectation is always sequence dependent and its use automatically ends with a call to `verify`:

    def mock = new MockFor(Person)      (1)
    mock.demand.getFirst{ 'dummy' }
    mock.demand.getLast{ 'name' }
    mock.use {                          (2)
        def mary = new Person(first:'Mary', last:'Smith')
        def f = new Family(mother:mary)
        assert f.nameOfMother() == 'dummy name'
    }
    mock.expect.verify()                (3)

1 | a new mock is created by a new instance of `MockFor`
2 | a `Closure` is passed to `use` which enables the mocking functionality
3 | a call to `verify` checks whether the sequence and number of method calls is as expected

The `StubFor` class supports (typically unit) testing of classes in isolation by allowing a loosely-ordered expectation of the behavior of collaborators to be defined. A typical test scenario involves a class under test and one or more collaborators. In such a scenario it is often desirable to just test the business logic of the CUT. One strategy for doing that is to replace the collaborator instances with simplified stub objects to help isolate out the logic in the target class. `StubFor` allows such stubs to be created using meta-programming. The desired behavior of collaborators is defined as a behavior specification.

In contrast to `MockFor` the stub expectation checked with `verify` is sequence independent and its use is optional:

    def stub = new StubFor(Person)      (1)
    stub.demand.with {                  (2)
        getLast{ 'name' }
        getFirst{ 'dummy' }
    }
    stub.use {                          (3)
        def john = new Person(first:'John', last:'Smith')
        def f = new Family(father:john)
        assert f.father.first == 'dummy'
        assert f.father.last == 'name'
    }
    stub.expect.verify()                (4)

1 | a new stub is created by a new instance of `StubFor`
2 | the `with` method is used for delegating all calls inside the closure to the `StubFor` instance
3 | a `Closure` is passed to `use` which enables the stubbing functionality
4 | a call to `verify` (optional) checks whether the number of method calls is as expected

`MockFor` and `StubFor` can not be used to test statically compiled classes e.g. for Java classes or Groovy classes that make use of `@CompileStatic`. To stub and/or mock these classes you can use Spock or one of the Java mocking libraries.

#### 2.2.4. Expando Meta-Class (EMC)

Groovy includes a special `MetaClass` the so-called `ExpandoMetaClass` (EMC). It allows to dynamically add methods, constructors, properties and static methods using a neat closure syntax.

Every `java.lang.Class` is supplied with a special `metaClass` property that will give a reference to an `ExpandoMetaClass` instance. The expando metaclass is not restricted to custom classes, it can be used for JDK classes like for example `java.lang.String` as well:

    String.metaClass.swapCase = {->
        def sb = new StringBuffer()
        delegate.each {
            sb << (Character.isUpperCase(it as char) ? Character.toLowerCase(it as char) :
                Character.toUpperCase(it as char))
        }
        sb.toString()
    }

    def s = "heLLo, worLD!"
    assert s.swapCase() == 'HEllO, WORld!'

The `ExpandoMetaClass` is a rather good candidate for mocking functionality as it allows for more advanced stuff like mocking static methods

    class Book {
        String title
    }

    Book.metaClass.static.create << { String title -> new Book(title:title) }

    def b = Book.create("The Stand")
    assert b.title == 'The Stand'

or even constructors

    Book.metaClass.constructor << { String title -> new Book(title:title) }

    def b = new Book("The Stand")
    assert b.title == 'The Stand'

| Mocking constructors might seem like a hack that’s better not even to be considered but even there might be valid use cases. An example can be found in Grails where domain class constructors are added at run-time with the help of `ExpandoMetaClass`. This lets the domain object register itself in the Spring application context and allows for injection of services or other beans controlled by the dependency-injection container.

If you want to change the `metaClass` property on a per test method level you need to remove the changes that were done to the metaclass, otherwise those changes would be persistent across test method calls. Changes are removed by replacing the metaclass in the `GroovyMetaClassRegistry`:

    GroovySystem.metaClassRegistry.removeMetaClass(String)

Another alternative is to register a `MetaClassRegistryChangeEventListener`, track the changed classes and remove the changes in the cleanup method of your chosen testing runtime. A good example can be found in the Grails web development framework.

Besides using the `ExpandoMetaClass` on a class-level, there is also support for using the metaclass on a per-object level:

    def b = new Book(title: "The Stand")
    b.metaClass.getTitle {-> 'My Title' }

    assert b.title == 'My Title'

In this case the metaclass change is related to the instance only. Depending on the test scenario this might be a better fit than the global metaclass change.

### 2.3. GDK Methods

The following section gives a brief overview on GDK methods that can be leveraged in test case scenarios, for example for test data generation.

#### 2.3.1. Iterable#combinations

The `combinations` method that is added on `java.lang.Iterable` compliant classes can be used to get a list of combinations from a list containing two or more sub-lists:

    void testCombinations() {
        def combinations = [[2, 3],[4, 5, 6]].combinations()
        assert combinations == [[2, 4], [3, 4], [2, 5], [3, 5], [2, 6], [3, 6]]
    }

The method could be used in test case scenarios to generate all possible argument combinations for a specific method call.

#### 2.3.2. Iterable#eachCombination

The `eachCombination` method that is added on `java.lang.Iterable` can be used to apply a function (or in this case a `groovy.lang.Closure`) to each if the combinations that has been built by the `combinations` method:

`eachCombination` is a GDK method that is added to all classes conforming to the `java.lang.Iterable` interface. It applies a function on each combination of the input lists:

    void testEachCombination() {
        [[2, 3],[4, 5, 6]].eachCombination { println it[0] + it[1] }
    }

The method could be used in the testing context to call methods with each of the generated combinations.

### 2.4. Tool Support

#### 2.4.1. Test Code Coverage

Code coverage is a useful measure of the effectiveness of (unit) tests. A program with high code coverage has a lower chance to hold critical bugs than a program with no or low coverage. To get code coverage metrics, the generated byte-code usually needs to be instrumented before the tests are executed. One tool with Groovy support for this task is Cobertura.

The following code listing shows an example on how to enable Cobertura test coverage reports in a Gradle build script from a Groovy project:

    def pluginVersion = '<plugin version>'
    def groovyVersion = '<groovy version>'
    def junitVersion = '<junit version>'

    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.eriwen:gradle-cobertura-plugin:${pluginVersion}'
        }
    }

    apply plugin: 'groovy'
    apply plugin: 'cobertura'

    repositories {
        mavenCentral()
    }

    dependencies {
        compile "org.codehaus.groovy:groovy-all:${groovyVersion}"
        testCompile "junit:junit:${junitVersion}"
    }

    cobertura {
        format = 'html'
        includes = ['**/*.java', '**/*.groovy']
        excludes = ['com/thirdparty/**/*.*']
    }

Several output formats can be chosen for Cobertura coverage reports and test code coverage reports can be added to continuous integration build tasks.

## 3. Testing with JUnit

Groovy simplifies JUnit testing in the following ways:

- You use the same overall practices as you would when testing with Java but you can adopt much of Groovy’s concise syntax in your tests making them succinct. You can even use the capabilities for writing testing domain specific languages (DSLs) if you feel so inclined.

- There are numerous helper classes that simplify many testing activities. The details differ in some cases depending on the version of JUnit you are using. We’ll cover those details shortly.

- Groovy’s PowerAssert mechanism is wonderful to use in your tests

- Groovy deems that tests are so important you should be able to run them as easily as scripts or classes. This is why Groovy includes an automatic test runner when using the `groovy` command or the GroovyConsole. This gives you some additional options over and above running your tests

In the following sections we will have a closer look at JUnit 3, 4 and 5 Groovy integration.

### 3.1. JUnit 3

Maybe one of the most prominent Groovy classes supporting JUnit 3 tests is the `GroovyTestCase` class. Being derived from `junit.framework.TestCase` it offers a bunch of additional methods that make testing in Groovy a breeze.

| Although `GroovyTestCase` inherits from `TestCase` doesn’t mean you can’t use JUnit 4 features in your project. In fact, the most recent Groovy versions come with a bundled JUnit 4 and that comes with a backwards compatible `TestCase` implementation. There have been some discussion on the Groovy mailing-list on whether to use `GroovyTestCase` or JUnit 4 with the result that it is mostly a matter of taste, but with `GroovyTestCase` you get a bunch of methods for free that make certain types of tests easier to write.

In this section, we will have a look at some of the methods provided by `GroovyTestCase`. A full list of these can be found in the JavaDoc documentation for groovy.test.GroovyTestCase , don’t forget it is inherited from `junit.framework.TestCase` which inherits all the `assert*` methods.

#### 3.1.1. Assertion Methods

`GroovyTestCase` is inherited from `junit.framework.TestCase` therefore it inherits a large number of assertion methods being available to be called in every test method:

    class MyTestCase extends GroovyTestCase {

        void testAssertions() {
            assertTrue(1 == 1)
            assertEquals("test", "test")

            def x = "42"
            assertNotNull "x must not be null", x
            assertNull null

            assertSame x, x
        }

    }

As can be seen above, in contrast to Java it is possible to leave out the parenthesis in most situations which leads to even more readability of JUnit assertion method call expressions.

An interesting assertion method that is added by `GroovyTestCase` is `assertScript`. It ensures that the given Groovy code string succeeds without any exception:

    void testScriptAssertions() {
        assertScript '''
            def x = 1
            def y = 2

            assert x + y == 3
        '''
    }

#### 3.1.2. shouldFail Methods

`shouldFail` can be used to check whether the given code block fails or not. In case it fails, the assertion does hold, otherwise the assertion fails:

    void testInvalidIndexAccess1() {
        def numbers = [1,2,3,4]
        shouldFail {
            numbers.get(4)
        }
    }

The example above uses the basic `shouldFail` method interface that takes a `groovy.lang.Closure` as a single argument. The `Closure` instance holds the code that is supposed to be breaking during run-time.

If we wanted to assert `shouldFail` on a specific `java.lang.Exception` type we could have done so by using the `shouldFail` implementation that takes the `Exception` class as first argument and the `Closure` as second argument:

    void testInvalidIndexAccess2() {
        def numbers = [1,2,3,4]
        shouldFail IndexOutOfBoundsException, {
            numbers.get(4)
        }
    }

If anything other than `IndexOutOfBoundsException` (or a descendant class of it) is thrown, the test case will fail.

A pretty nice feature of `shouldFail` hasn’t been visible so far: it returns the exception message. This is really useful if you want to assert on the exception error message:

    void testInvalidIndexAccess3() {
        def numbers = [1,2,3,4]
        def msg = shouldFail IndexOutOfBoundsException, {
            numbers.get(4)
        }
        assert msg.contains('Index: 4, Size: 4') ||
            msg.contains('Index 4 out-of-bounds for length 4') ||
            msg.contains('Index 4 out of bounds for length 4')
    }

#### 3.1.3. notYetImplemented Method

The `notYetImplemented` method has been greatly influenced by HtmlUnit. It allows to write a test method but mark it as not yet implemented. As long as the test method fails and is marked with `notYetImplemented` the test goes green:

    void testNotYetImplemented1() {
        if (notYetImplemented()) return   (1)

        assert 1 == 2                     (2)
    }

1 | a call to `notYetImplemented` is necessary for `GroovyTestCase` to get the current method stack.
2 | as long as the test evaluates to `false` the test execution will be successful.

An alternative to the `notYetImplemented` method is the `@NotYetImplemented` annotation. It allows for annotating a method as not yet implemented, with the exact same behavior as `GroovyTestCase#notYetImplemented` but without the need for the `notYetImplemented` method call:

    @NotYetImplemented
    void testNotYetImplemented2() {
        assert 1 == 2
    }

### 3.2. JUnit 4

Groovy can be used to write JUnit 4 test cases without any restrictions. The `groovy.test.GroovyAssert` holds various static methods that can be used as replacement for the `GroovyTestCase` methods in JUnit 4 tests:

    import org.junit.Test

    import static groovy.test.GroovyAssert.shouldFail

    class JUnit4ExampleTests {

        @Test
        void indexOutOfBoundsAccess() {
            def numbers = [1,2,3,4]
            shouldFail {
                numbers.get(4)
            }
        }

    }

As can be seen in the example above, the static methods found in `GroovyAssert` are imported at the beginning of the class definition thus `shouldFail` can be used the same way it can be used in a `GroovyTestCase`.

| `groovy.test.GroovyAssert` descends from `org.junit.Assert` that means it inherits all JUnit assertion methods. However, with the introduction of the power assertion statement, it turned out to be good practice to rely on assertion statements instead of using the JUnit assertion methods with the improved message being the main reason.

It is worth mentioning that `GroovyAssert.shouldFail` is not absolutely identical to `GroovyTestCase.shouldFail`. While `GroovyTestCase.shouldFail` returns the exception message, `GroovyAssert.shouldFail` returns the exception itself. It takes a few more keystrokes to get the message, but in return you can access other properties and methods of the exception:

    @Test
    void shouldFailReturn() {
        def e = shouldFail {
            throw new RuntimeException('foo',
                                       new RuntimeException('bar'))
        }
        assert e instanceof RuntimeException
        assert e.message == 'foo'
        assert e.cause.message == 'bar'
    }

### 3.3. JUnit 5

Much of the approach and helper classes described under JUnit4 apply when using JUnit5 however JUnit5 uses some slightly different class annotations when writing your tests. See the JUnit5 documentation for more details.

Create your test classes as per normal JUnit5 guidelines as shown in this example:

    class MyTest {
      @Test
      void streamSum() {
        assertTrue(Stream.of(1, 2, 3)
          .mapToInt(i -> i)
          .sum() > 5, () -> "Sum should be greater than 5")
      }

      @RepeatedTest(value=2, name = "{displayName} {currentRepetition}/{totalRepetitions}")
      void streamSumRepeated() {
        assert Stream.of(1, 2, 3).mapToInt(i -> i).sum() == 6
      }

      private boolean isPalindrome(s) { s == s.reverse()  }

      @ParameterizedTest                                                              (1)
      @ValueSource(strings = [ "racecar", "radar", "able was I ere I saw elba" ])
      void palindromes(String candidate) {
        assert isPalindrome(candidate)
      }

      @TestFactory
      def dynamicTestCollection() {[
        dynamicTest("Add test") { -> assert 1 + 1 == 2 },
        dynamicTest("Multiply Test", () -> { assert 2 * 3 == 6 })
      ]}
    }

1 | This test requires the additional `org.junit.jupiter:junit-jupiter-params` dependency if not already in your project.

You can run the tests in your IDE or build tool if it supports and is configured for JUnit5. If you run the above test in the GroovyConsole or via the `groovy` command, you will see a short text summary of the result of running the test:

    JUnit5 launcher: passed=8, failed=0, skipped=0, time=246ms

More detailed information is available at the `FINE` logging level. You can configure your logging to display such information or do it programmatically as follows:

    @BeforeAll
    static void init() {
      def logger = Logger.getLogger(LoggingListener.name)
      logger.level = Level.FINE
      logger.addHandler(new ConsoleHandler(level: Level.FINE))
    }

## 4. Testing with Spock

Spock is a testing and specification framework for Java and Groovy applications. What makes it stand out from the crowd is its beautiful and highly expressive specification DSL. In practice, Spock specifications are written as Groovy classes. Although written in Groovy they can be used to test Java classes. Spock can be used for unit, integration or BDD (behavior-driven-development) testing, it doesn’t put itself into a specific category of testing frameworks or libraries.

| Beside these awesome features Spock is a good example on how to leverage advanced Groovy programming language features in third party libraries, for example, by using Groovy AST transformations.

| This section should not serve as detailed guide on how to use Spock, it should rather give an impression what Spock is about and how it can be leveraged for unit, integration, functional or any other type of testing.

The next section we will have a first look at the anatomy of a Spock specification. It should give a pretty good feeling on what Spock is up to.

### 4.1. Specifications

Spock lets you write specifications that describe features (properties, aspects) exhibited by a system of interest. The "system" can be anything between a single class and an entire application, a more advanced term for it is system under specification. The feature description starts from a specific snapshot of the system and its collaborators, this snapshot is called the feature’s fixture.

Spock specification classes are derived from `spock.lang.Specification`. A concrete specification class might consist of fields, fixture methods, features methods and helper methods.

Let’s have a look at a simple specification with a single feature method for an imaginary `Stack` class:

    class StackSpec extends Specification {

        def "adding an element leads to size increase"() {  (1)
            setup: "a new stack instance is created"        (2)
                def stack = new Stack()

            when:                                           (3)
                stack.push 42

            then:                                           (4)
                stack.size() == 1
        }
    }

1 | Feature method, is by convention named with a String literal.
2 | Setup block, here is where any setup work for this feature needs to be done.
3 | When block describes a stimulus, a certain action under target by this feature specification.
4 | Then block any expressions that can be used to validate the result of the code that was triggered by the when block.

Spock feature specifications are defined as methods inside a `spock.lang.Specification` class. They describe the feature by using a String literal instead of a method name.

A feature method holds multiple blocks, in our example we used `setup`, `when` and `then`. The `setup` block is special in that it is optional and allows to configure local variables visible inside the feature method. The `when` block defines the stimulus and is a companion of the `then` block which describes the response to the stimulus.

Note that the `setup` method in the `StackSpec` above additionally has a description String. Description Strings are optional and can be added after block labels (like `setup`, `when`, `then`).

### 4.2. More Spock

Spock provides much more features like data tables or advanced mocking capabilities. Feel free to consult the Spock GitHub page for more documentation and download information.

## 5. Functional Tests with Geb

Geb is a functional web testing and scraper library that integrates with JUnit and Spock. It is based upon the Selenium web drivers and, like Spock, provides a Groovy DSL to write functional tests for web applications.

Geb has great features that make it a good fit for a functional testing library:

- DOM access via a JQuery-like `$` function

- implements the page pattern

- support for modularization of certain web components (e.g. menu-bars, etc.) with modules

- integration with JavaScript via the JS variable

| This section should not serve as detailed guide on how to use Geb, it should rather give an impression what Geb is about and how it can be leveraged functional testing.

The next section will give an example on how Geb can be used to write a functional test for a simple web page with a single search field.

### 5.1. A Geb Script

Although Geb can be used standalone in a Groovy script, in many scenarios it’s used in combination with other testing frameworks. Geb comes with various base classes that can be used in JUnit 3, 4, TestNG or Spock tests. The base classes are part of additional Geb modules that need to be added as a dependency.

For example, the following `@Grab` dependencies can be used to run Geb with the Selenium Firefox driver in JUnit4 tests. The module that is needed for JUnit 3/4 support is `geb-junit4`:

    @Grab('org.gebish:geb-core:0.9.2')
    @Grab('org.gebish:geb-junit4:0.9.2')
    @Grab('org.seleniumhq.selenium:selenium-firefox-driver:2.26.0')
    @Grab('org.seleniumhq.selenium:selenium-support:2.26.0')

The central class in Geb is the `geb.Browser` class. As its name implies it is used to browse pages and access DOM elements:

    import geb.Browser
    import org.openqa.selenium.firefox.FirefoxDriver

    def browser = new Browser(driver: new FirefoxDriver(), baseUrl: 'http://myhost:8080/myapp')  (1)
    browser.drive {
        go "/login"                        (2)

        $("#username").text = 'John'       (3)
        $("#password").text = 'Doe'

        $("#loginButton").click()

        assert title == "My Application - Dashboard"
    }

1 | A new `Browser` instance is created. In this case it uses the Selenium `FirefoxDriver` and sets the `baseUrl`.
2 | `go` is used to navigate to a URL or relative URI
3 | `$` together with CSS selectors is used to access the `username` and `password` DOM fields.

The `Browser` class comes with a `drive` method that delegates all method/property calls to the current `browser` instance. The `Browser` configuration must not be done inline, it can also be externalized in a `GebConfig.groovy` configuration file for example. In practice, the usage of the `Browser` class is mostly hidden by Geb test base classes. They delegate all missing properties and method calls to the current `browser` instance that exists in the background:

    class SearchTests extends geb.junit4.GebTest {

        @Test
        void executeSearch() {
            go 'http://somehost/mayapp/search'              (1)
            $('#searchField').text = 'John Doe'             (2)
            $('#searchButton').click()                      (3)

            assert $('.searchResult a').first().text() == 'Mr. John Doe' (4)
        }
    }

1 | `Browser#go` takes a relative or absolute link and calls the page.
2 | `Browser#$` is used to access DOM content. Any CSS selectors supported by the underlying Selenium drivers are allowed
3 | `click` is used to click a button.
4 | `$` is used to get the first link out of the `searchResult` block

The example above shows a simple Geb web test with the JUnit 4 base class `geb.junit4.GebTest`. Note that in this case the `Browser` configuration is externalized. `GebTest` delegates methods like `go` and `$` to the underlying `browser` instance.

### 5.2. More Geb

In the previous section we only scratched the surface of the available Geb features. More information on Geb can be found at the project homepage.