(Quick Reference)

12 Testing - Reference Documentation

Authors: Andres Almiray

Version: 1.5.0

12 Testing

Automated testing is seen as a key part of Griffon, implemented using Groovy Tests. Hence, Griffon provides many ways to making testing easier from low level unit testing to high level integration tests. This section details the different capabilities that Griffon offers in terms of testing.

The first thing to be aware of is that all of the create-* commands actually end up creating unit tests automatically for you. For example say you run the create-mvc command as follows:

griffon create-mvc com.yourcompany.yourapp.simple

Not only will Griffon create an MVC group with a controller at griffon-app/controllers/com/yourcompany/yourapp/SimpleController.groovy, but also an integration test at test/integration/com/yourcompany/yourapp/SimpleControllerTests.groovy. What Griffon won't do however is populate the logic inside the test! That is left up to you.

As of Griffon 0.9, the suffix of Test is also supported for test cases.

Running Tests

Test are run with the test-app command:

griffon test-app

The above command will produce output such as:

Running Unit Tests…
Running test FooTests...FAILURE
Unit Tests Completed in 464ms …

Tests failed: 0 errors, 1 failures

Whilst reports will have been written out the target/test-reports directory.

You can force a clean before running tests by passing -clean to the test-app command.

Targeting Tests

You can selectively target the test(s) to be run in different ways. To run all tests for a controller named SimpleController you would run:

griffon test-app SimpleController

This will run any tests for the class named SimpleController. Wildcards can be used...

griffon test-app *Controller

This will test all classes ending in Controller. Package names can optionally be specified...

griffon test-app some.org.*Controller

or to run all tests in a package...

griffon test-app some.org.*

or to run all tests in a package including subpackages...

griffon test-app some.org.**

You can also target particular test methods...

griffon test-app SimpleController.testLogin

This will run the testLogin test in the SimpleController tests. You can specify as many patterns in combination as you like...

griffon test-app some.org.* SimpleController.testLogin BookController

Targeting Test Types and/or Phases

In addition to targeting certain tests, you can also target test types and/or phases by using the phase:type syntax.

Griffon organises tests by phase and by type. A test phase relates to the state of the Griffon application during the tests, and the type relates to the testing mechanism.

Griffon comes with support for 3 test phases (unit, integration, and other) and JUnit test types for the unit and integration phases. These test types have the same name as the phase.

Testing plugins may provide new test phases or new test types for existing phases. Refer to the plugin documentation.

To execute the JUnit integration tests you can run:

griffon test-app integration:integration

Both phase and type are optional. Their absence acts as a wildcard. The following command will run all test types in the unit phase:

griffon test-app unit:

The Griffon Spock Plugin is one plugin that adds new test types to Griffon. It adds a spock test type to the unit andintegration phases. To run all spock tests in all phases you would run the following:

griffon test-app :spock

To run the all of the spock tests in the integration phase you would run...

griffon test-app integration:spock

More than one pattern can be specified...

griffon test-app unit:spock integration:spock

Targeting Tests in Types and/or Phases

Test and type/phase targetting can be applied at the same time:

griffon test-app integration: unit: some.org.**

This would run all tests in the integration and unit phases that are in the page some.org or a subpackage of.

12.1 Unit Testing

Unit testing are tests at the "unit" level. In other words you are testing individual methods or blocks of code without considering for surrounding infrastructure. The following is an unit test created using the default template

import griffon.test.*

class SomeUnitTests extends GriffonUnitTestCase { protected void setUp() { super.setUp() }

protected void tearDown() { super.tearDown() }

void testSomething() {

} }

You have access to all mocking facilities exposed by GriffonUnitTestCase within this test.

12.2 Integration Testing

Integration tests differ from unit tests in that you have full access to the Griffon application within the test. The following is an integration test created using the default template

import griffon.core.GriffonApplication
import griffon.test.*

class SomeControllerTests extends GriffonUnitTestCase { GriffonApplication app

protected void setUp() { super.setUp() }

protected void tearDown() { super.tearDown() }

void testSomething() { } }

As with unit tests, you have access to all mocking facilities exposed by GriffonUnitTestCase within this test, but you also have access to a full running Griffon application. By default this application is bootstrapped to the INITIALIZE phase. It's up to you to instruct the application to move to another phase depending on what you want to test (refer to startup(), ready(), realize() and show() methods).

The type of application to be run depends on the type of project and/or a configuration flag as explained next:

  • if a configuration flag griffon.application.mainClass exists then its value will be used (assumes the value is a literal full qualified class).
  • if the project is an addon then it will use griffon.test.mock.MockApplication
  • finally it will fall back to griffon.swing.SwingApplication

12.3 Mocking

Mocking is but one of the many alternatives you have at your disposal to reduce complexity while setting up a test that requires a good number of components to be setup before actually testing the real class under test. Griffon provides a few mocking helper methods and classes, which will be discussed next.

12.3.1 MockGriffonApplication

MockGriffonApplication is a fully functional GriffonApplication with the advantage that it lets you override the location of all configuration classes: Application, Builder, Config and Events.

If you choose to change the default UIThreadHandler then you must do it so right after the application has been instantiated and no other operation that requires multi-thread access has been called, otherwise you won't be able to change it's value.

By default, a MockGriffonApplication defines the following:

  • MockApplication - setups a 'mock' MVC group with 3 elements: MockModel, MockView and MockController
  • MockBuilderConfig - defines a single builder entry: griffon.test.mock.MockBuilder
  • MockConfig - defines a single config entry: mocked = true
  • MockEvents - defines an event handler for 'Mock'

The remaining classes have these settings:

  • MockBuilder - a single node named mock that returns a map with any properties that were defined on the node.
  • MockModel - a lone observable property value of type String.
  • MockView - simple script that calls the mock node defined by the builder.
  • MockController - a controller with no actions.