Skip to content
Jason R. Clark edited this page Nov 29, 2015 · 1 revision

Testing Shoes

Shoes 4 is developed in a TDD style. You should be writing and running the specs. But with a project of this size, it can be hard to get your footing. This page should help you understand the testing layout in Shoes, and give you some tips and tricks along the way.

Where are the Specs?

Shoes 4 is split into a [few separate gems](Gem structure), specifically to enable running with a different UI backend at some point in the future. This gives us a couple different main locations where specs can be found:

  • shoes-core/spec - specs against the main Shoes DSL, relying only on a 'mock' backend (more on that in a moment)
  • shoes-swt/spec - specs for the current default backend implementation based on SWT + JRuby
  • shoes-package/spec - specs for Shoes' packaging functionality

When you know the purpose of each of the separate gems, it's a bit clearer what should be tested in each location.

  • shoes-core/spec tests out DSL logic and algorithms and potentially interaction the DSL has with the backend.
  • shoes-swt/spec tests out how the backend directly integrates with the underlying SWT library. Much, although not all, of this will be done via expectations and mocking.
  • shoes-package/spec tests out anything related to packaging. It actually creates files on disk to accomplish this testing end-to-end (i.e. integration testing)

Good Examples?

Many of the tests in shoes-core look similar, since they often serve very similar roles--take values from the user, send them along to the backend. Among the simpler examples is shoes-core/spec/shoes/progress_spec.rb

A simple example from shoes-swt is shoes-swt/spec/shoes/swt/color_spec.rb. A more complex example of interactions with SWT can be found in shoes-swt/spec/shoes/swt/key_listener_spec.rb

The Mock Backend

So what's this mock backend that we talked about shoes-core using? When the specs for shoes-core are run, we load up a fake backend implementation from shoes-core/lib/shoes/mock/*. Any method that the DSL expects to call against a backend should be implemented here (since some DSL code under test much call out to the mock backend, right?)

The mock backend serves two purposes then: it exists to let the DSL tests run without loading a full UI backend, and it is documentation of the methods that the DSL will call on a backend. When a new backend implementation gets started, the mock backend would be a great place to start since it essentially lists all the methods you need to provide!

Testing the DSL with SWT

The specs against the DSL in shoes-core are also loaded when you run the specs under shoes-swt. This provides us with additional coverage to make certain that the backend is not breaking any expectations the DSL has of it.

Running Specs

The easiest way to get started running specs are the available rake tasks. Some examples (run rake --tasks to see a more complete list):

$ rake spec                      # Run the whole spec suite
$ rake spec:core                 # Run integration specs using the mock backend
$ rake spec:swt                  # Run integration specs using the Swt backend, plus isolation specs for the Swt backend
$ rake spec:package              # Run specs for Shoes packaging

$ rake spec:swt:isolation        # Run isolation specs for the Swt backend
$ rake spec:swt:integration      # Run integration specs using the Swt backend

$ rake spec[Shape]               # Run the whole spec suite, but only for Shape
$ rake spec:core[Shape]          # Run integration specs for Shape using the mock backend
$ rake spec:swt[Shape]           # Run integration and isolation specs for Shape, using the Swt backend
$ rake spec:swt:isolation[Shape] # Run isolation specs for Shape using the Swt backend

Note: For Windows, C:\tmp\shoes4>jruby -S rake spec

Running Individual Spec Files

Sometimes you only want to run specs from individual files rather than entire suites. You can run individual specs from the project root directory like this:

$ rspec shoes-swt/spec/shoes/swt/app_spec.rb

If you're on OS X and you are running specs that require SWT, you will have to set the JRUBY_OPTS environment variable first:

$ export JRUBY_OPTS=-J-XstartOnFirstThread
$ rspec shoes-swt/spec/shoes/swt/app_spec.rb

or set JRUBY_OPTS directly on the command line:

$ JRUBY_OPTS=-J-XstartOnFirstThread rspec shoes-swt/spec/shoes/swt/app_spec.rb

Running DSL Specs with SWT Loaded

As mentioned earlier, if we run a spec from shoes-core it will use the backend. What if we wanted to run one of those files but with the SWT backend loaded?

While there's not a perfect fix, you can get around this easily by running an additional spec file from shoes-swt, which will force the SWT backend to load.

$ rspec shoes-swt/spec/shoes/swt/app_spec.rb shoes-core/spec/shoes/app_spec.rb

Now when shoes-core/spec/shoes/app_spec.rb is run, it'll be with SWT loaded.

Integration vs Isolation Specs

There are two kinds of Shoes 4 specs:

  1. Integration specs: These specify the functionality of the Shoes DSL. They can be run with any compatible Shoes backend. Shoes 4 comes with a mock backend and an SWT backend that can run the integration specs.

  2. Isolation specs: These specify the internal behavior of a Shoes backend, in isolation from the DSL. Shoes 4 comes with an isolation spec suite for the SWT backend.

Mocking and Stubbing

RSpec's mocking and stubbing support comes in very useful throughout Shoes. Some general principles to keep in mind:

  • If you're testing in shoes-core, use expect and mocking in general to test the border between the DSL and the backend. Code entirely within the DSL should ideally be testable without resorting to mocking.
  • Similarly, when testing in shoes-swt you will often need to stub out or mock various behaviors in the swt gem we use to access the underlying UI library.
  • In shoes-swt specs, you may also find it necessary to stub out the DSL for your backend components. This is because the lifetimes are backward (i.e. DSL's create backend objects) which poses some issues for properly wiring up tests.

Lots more good advice on spec'ing can be found at http://betterspecs.org/