The blog post Cucumber and Full Stack Testing by @tooky sparked a very interesting Twitter conversation, during the course of which I realised I had fairly clear views on what tests to write for a web application. Assuming an intention to create (or at least work towards creating) a hexagonal architecture, here are the tests I would ideally aim to have at some point:
- A couple of end-to-end tests that hit the UI and the database, to prove that we have at least one configuration in which those parts join up. These only need to be run rarely, say on CI and maybe after each deployment.
- An integration test for each adapter, proving that the adapter meets its contract with the domain objects AND that it works correctly with whatever external service it is adapting. This applies to the views-and-controllers pairings too, with the service objects in the middle hexagon stubbed or mocked as appropriate. These will each need to run when the adapters or the external services change, which should be infrequent once initial development of an adapter has settled out.
- Unit tests for each object in the middle hexagon, in which commands issued to other objects are mocked (see @sandimetz‘s testing rules, for which I have no public link). And for every mocked interaction, a contract test proving that the mocked object really would respond as per the mocked interaction (see @jbrains‘s Integrated tests are a scam articles). These will be extremely fast, and will be run every few seconds during the TDD cycle.
I’ve never yet reached this goal, but that’s what I’m striving for when I create tests. It seems perfectly adequate to me, given sufficient discipline around the creation of the contract tests. Have I missed anything? Would it give you confidence in your app?
Interesting article and blog!
Seems like a good approach.
I’ve been building apps like this for a while:
* Integrated tests for DB-queries.
* Unit tests for everything in between (rails-free where possible).
* Request tests for each path through the controller (usually only success and failure).
This means I have very slim controllers and views with very little logic. Controller logic goes into services and view logic into presenters.
I haven’t used contract tests very much, although I like the idea. The few integrated tests I do have seems to be enough to ensure the parts work together.
@joakim Cool. Do you have any real code you can share?
It’s mostly tied up in closed source apps.
I have a small app I’m working on that are built that way. It also goes a step further to be able to have models that don’t inherit from ActiveRecord.
https://github.com/joakimk/deployer
Just remembered, I wrote a blog post with a high level overview of a feature designed that way 6 month ago, http://rubyblocks.se/2012/06/29/experiences-designing-a-unit-testable-feature/.
It’s still in use. We refactored it today before changing it a bit, but the basic design still holds.
I suppose if the idea of acceptance testing your hexagon feels dangerous it may indicate program behaviour is present in your adapters. Interesting.
That’s a great way of expressing it, yes.