Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
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?
- Running Specs
- Mocking and Stubbing
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/spectests out DSL logic and algorithms and potentially interaction the DSL has with the backend.
shoes-swt/spectests 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/spectests out anything related to packaging. It actually creates files on disk to accomplish this testing end-to-end (i.e. integration testing)
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
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.
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
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
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:
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.
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
expectand 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-swtyou will often need to stub out or mock various behaviors in the
swtgem we use to access the underlying UI library.
shoes-swtspecs, 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/