Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

DRYing up Jasmine Specs with Shared Behavior

When writing nicely encapsulated code and you have a group of objects that share an interface (pick your favorite patterns), you often want to share your test code as well. If the system models financial accounts with credits and debits, and you make a change to the reconciliation code, you want to run a core set of specs against all cash, loan, and credit card account objects.

People ask how to do this in JavaScript on the Jasmine mailing list every so often.

So here’s an example of “Shared Example Groups” in Jasmine.

This Game spec looks totally fine for a basic ball game. But what if I want to have multiple different types of ball games?

Here are specs for Basketball and (American) Football:

The specs related to the Game itself are inline. That doesn’t feel very DRY and really, we want to test the interface with the same code. We’re working in JavaScript. So we write a function.

Jasmine works by building up all the functions to execute at spec run time. When you call describe, the passed-in function is executed immediately. Inside the describe, the calls to beforeEach, afterEach and it queue up the passed-in functions for execution later, when you want to run your specs.

This means you can put all of your shared specs, including any beforeEach calls, in a function that can be executed as needed. Like this:

Each time sharedBehaviorForGameOf is called, the three before and two spec functions are queued up. Call it twice and you’ll wind up with four new specs in your Jasmine environment.

And since it’s a function, yes, you can pass parameters. The context parameter can be used to pass in a ball and a game for use in the shared specs. Since the “(shared)” describe function is called each time sharedBehaviorForGameOf is called, there will be a separate closure for the local ball and game.

So now we can refactor our specs to use our function.

This is a useful technique, but use it appropriately and with a little caution. Use it in situations for consistent testing, not just to DRY up your specs for DRY-ness’s sake.

Keep the varied behavior (like the field goal scoring above) outside your shared behavior function instead of using the parameters. The parameters should be for the object(s) under test, not their behavior.

And lastly, (as always) keep your mind on your JavaScript closures.

  1. Thanks for posting this!

    Might help me reduce the spec I’m working on with several lines of code.

  2. Sebastian says:

    Argh, Murphy’s Law, huh? Of course the interesting part is missing:

    “This means you can put all of your shared specs, including any beforeEach calls, in a function that can be executed as needed. Like this:”


  3. Sebastian says:

    And I want to add that your commenting system doesn’t work or at least doesn’t provide any feedback if the posting was successful.

  4. Scott Silvi says:

    The code block for sharedBehaviorForGameOf is missing. However I did find it on this SO post: that references this article.

  5. Davis W. Frank says:

    Scott – thanks for the find. No clue why it wasn’t showing up. But it should be there now.

  6. Brent Wheeldon says:

    We had some trouble scoping these with CoffeeScript (particularly the object passed the the shared example method). We added a gist of how to get Davis’ example working in the brave new world of CoffeeScript. If anyone knows a cleaner way of doing it, please let us know!

  7. Davis W. Frank says:

    I’ve commented on the GIST. That game reference isn’t going where you want it to go.

  8. […] the JavaScript world, Mocha has shared behaviors, as does Jasmine.  I’m not sure about QUnit, but JavaScript is flexible enough that it probably […]

  9. Jerome says:

    Does this working with Jasmine 1.3 or just 2?

    I’ve been trying to get this to work without much success

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *