Specify Use Case: Models, Rules and Features

I introduced my Specify micro-framework in a previous post. In this post I want to cover an example of how effective I think this kind of approach can be.

This post will be short on details and heavy on code. My goal here is to show what I think is an interesting idea about providing a domain model for what you are working on.

Going with the example from my previous post, imagine you have a “planetary weight” application. This may have components like a REST interface as well as a web-based application. But somewhere in your logic you have elements that actually perform the calculations that allow someone’s weight on another planet to be calculated.

What I want Specify to do is serve as an abstraction layer over unit tests and integration tests. One way to do this is to test to a model. That model can specify the business rules (that you might normally unit test) and the features (that you might normally integration test).

So imagine you have a model like this:

Note the section under the comment Model Execution. That’s not the actual code of the application necessarily. In fact, in my case it’s not: the planetary app I wrote uses JavaScript. But what the above section of code does is provide a model of how that part of the application works. This allows me to test my assumptions about it.

So I could provide a Specify file like this:

Were you to run this, you get the following output:

Planet Weight Calculator
  Surface Gravity Calculation
    surface gravity can be calculated for all planets
      Earth surface gravity: 0.9984412061578731
      Mercury surface gravity: 0.3772098862532158
      Venus surface gravity: 0.9043801139180913
      Mars surface gravity: 0.3783130934843111
      Jupiter surface gravity: 2.5265121478475008
      Saturn surface gravity: 1.0644777190561834
      Uranus surface gravity: 0.9040641234578886
      Neptune surface gravity: 1.136103689974277
    weight is calculated based on surface gravity
      Earth weight: 199.68824123157464
      Mercury weight: 75.44197725064315
      Venus weight: 180.87602278361825
      Mars weight: 75.66261869686221
      Jupiter weight: 505.30242956950013
      Saturn weight: 212.89554381123668
      Uranus weight: 180.8128246915777
      Neptune weight: 227.22073799485537

Finished in 0.00268 seconds (files took 0.38298 seconds to load)
16 examples, 0 failures

So why would you do this? Note that this is not testing the web application at all. It’s simply allowing a model to be executed. This lets us know if we understand exactly how the model should be working. Further, it let’s us reinforce that view with developers or business folks.

For example, a business expert could look at the method find_surface_gravity_ratio_for in the model representation and determine if I’m executing it correctly.

When I want to test the web application itself, I can provide a Specify file for that as well:

The output from this will be the following:

Calculate Planet Weights
  a 200 pound person will weigh 75.6 on Mercury.
  a 200 pound person will weigh 181.4 on Venus.
  a 200 pound person will weigh 75.4 on Mars.
  a 200 pound person will weigh 472.8 on Jupiter.
  a 200 pound person will weigh 212.8 on Saturn.
  a 200 pound person will weigh 177.8 on Uranus.
  a 200 pound person will weigh 225 on Neptune.

Finished in 12.17 seconds (files took 0.35617 seconds to load)
7 examples, 0 failures

Note that this returning a calculation based on the same idea that my model went through. Yet there are differences. For example, the model reports that a 200 pound person would weigh 227.22 pounds on Neptune, whereas the web application is reporting 225. So what we can do is look at if those differences matter. They may be pointing out nothing more than expected deviations given floating point math or they may be pointing out flaws in our understanding of the model.

What I hope you notice in this is the way Specify lets you word your spec files. You can see that I used the Specify DSL slightly differently each time in order to accommodate what I was talking about.

The idea of building a domain model is important, particularly for application domains that are complex. In this example, my domain model serves double-duty: it serves as a mechanism for me to test underlying calculations of the model and also serves as a page object to allow a web service or page to be interacted with. Further, you can wrap these models in specific test DSLs to make the model, the application, and the tests for both more clear.

This is admittedly an area I’m still exploring with Specify but the idea of using a model along with rules and features seems like a promising area of exploration.


This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.