Stubbing Partials with RSpec in Rails View Tests

Working with my pair yesterday we ran into an issue testing a view that pulled in several partials. In the interest of making progress we punted after about half an hour of trying to setup expectations on the partials and just tested the negative cases where we didn’t have to worry about the partials being called. Intellectual curiosity and not wanting to leave the views lightly tested I dived into seeing how we could effectively test that the partials were called as expected.

Say you have a view like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="content">
<div id="page_title" style="padding-bottom: 20px;">
<h2>Books</h2>
</div>
< %= render :partial ='tabs' %>;

< % if @books.empty? -%>;
<em>No Books</em><em>
< % else %>
< %= pagination_links = render :partial => 'shared/pagination', :object => @books %>;
< %= render :partial => "book_rows", :locals => {:books => @books} %>
< %= pagination_links %>
< % end %>
</em>

</div>

You want to test the conditional to see that the partials to display the list of books work correctly. You don’t want to worry about concerns like setting up the books collection, and you might even want to stub out the call to the partial that displays the tabs a the top of the page.

The Rspec example group for this looks like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
require 'spec_helper'

describe "books.rhtml" do
  before(:each) do
    assigns[:books] = []
  end

  describe "with no books" do
    it "should display 'No Books' message" do
      render
      response.should have_text(/No Books/)
    end
  end

  describe "with books" do
    before(:each) do
      assigns[:books] = [Factory.build(:book)]
      template.stub(:render).and_call_original
      template.stub(:render).with(hash_including(:partial => "tabs"))
      template.stub(:render).with(hash_including(:partial => "shared/pagination"))
    end

    it "should render book rows" do
      template.should_receive(:render).with(hash_including(:partial => "book_rows"))
      render
    end
  end
end

The key find was to use with(:hash_including()) which I found from a helpful link at Stack Overflow.

Breaking the Build at the New Job

I broke the build

My first break of the CI build on a new team came about two weeks into starting the new job. We had made a small change to a dynamically created URL on a single page of the application. Normally this would fall into the category of “too simple to test” for me. My pairing partner pointed out when we started the story that we should put a test in for the change. I argued that changing a URL was too simple a change to bother writing a test for. He disagreed, but let me go ahead after some further discussion. After checking in the feature, about an hour later a developer on the other side of the room piped up with “Someone broke the build.” My pairing partner smiled and said, “I guess we didn’t need to test that.”

It turned out there was another test I didn’t realize had a dependency on that same link and by changing it we had broken an assertion on the specific URL. A bit embarrassed I learned an important lesson. My assumptions about “too simple to break” needed some adjusting.

Over the course of several weeks I came to appreciate that many things were worth testing. A particularly revealing example was testing a new javascript dialog. Javascript is always a pain point when it comes to unit testing, and I’ve often let that coverage of javascript functionality be covered by functional tests usually with Selenium. My pairing partner walked me through a complete TDD approach asserting every part of the function we created and the various DOM elements we used to create it. I did ask a few questions about whether we really needed to test that we had created a DOM element in some exact order at points, but he was firm about testing in every piece. By the end of the feature I had a new appreciation for doing very low level unit testing.

I love that I’m being challenged on not writing enough tests. For so long in past shops I was the hardcore TDD advocate constantly questioned about the real need for testing some component. Now I’m learning to test in even very small changes.

Cardboard Boxes and Modern Web Frameworks

My daughter spent an hour the other day cutting holes, drawing red bricks, and pasting grass along the bottom of a simple cardboard box. It’s a common story among parents, especially of small children that despite spending a lot of money on a gift, the kid ends up enjoying the box and ignoring the toy.

I’ve noticed a common quality of many newer web frameworks is that they provide you with a nice box to build from. Typically:

  • A default structure so you know where to find the models, views, controllers, extra libraries, etc.
  • A command line for generating stubs, running tests, and deploying.
  • A plugin system for easily adding functionality from swapping out javascript libraries to adding a security system.

Though there are probably others I’m aware of this model being used by Spring Roo, the Play Framework, Gryphon, Grails, and Rails. I don’t claim to be a historian on this, but Rails was my first experience with this style and I assume to be the originator of the approach.

The benefits of this approach are obvious from the first time you start off with a Hello World tutorial. For one you generally have a single download for the framework. After unpacking you’re able to use the command line to generate your Hello World controller, find the view in a predefined location, add the Hello World line, and fire up the application from the command line. Passing the 5 minute test is pretty important if you expect developers to give your framework a chance.

As a consultant working on numerous legacy code projects, there’s always the groan moment when you start looking into the code and you realize its non-obvious where to find things. I’ve seen libraries sprinkled about at random, key configuration files that were supposed to be moved into the users home directory, model classes mixed in with controllers, and a host of other inconsistencies. With a framework that reinforces the default structures it becomes easy to find things and much easier for plugin-authors to write plug-ins that make the framework much more valuable.

Finally, the plugin system is a critical part of new frameworks. Being able to add security framework on the fly, swap out your testing framework, or simply add in a nicer date library really starts to make things feel like magic. Indeed among these frameworks they are starting to push more and more modularity into the plugin systems to allow for the framework to evolve better over time.

I hope this trend continues in the world of web frameworks, as I really like a nice box to start a project from.

Mock With Spock

My default rule with mocking is to try to stick to stubs where possible. I don’t enjoy having to setup and verify interactions with mocks, but sometimes you have some code where that’s exactly what you need to do. I’ve used many frameworks in Java over the years from EasyMock to Mockito, but I was quite happy with how easy it was to do in Spock. I recently found myself having to build a test harness around some legacy code. The real world code was more involved, but it looked something like this:

1
2
3
4
5
6
7
8
9
10
11
public void addDefaultQuestions(Category category) {
  if (categoryDao.getCategory(category.getId()).getQuestions().isEmpty()) {
    for (Question question : category.getQuestions()) {
      if (question.isDefaultQuestion()) {
        categoryDao.addQuestion(question, true);
      } else {
        categoryDao.addQuestion(question, false);
      }
    }
  }
}

The method is taking a category, checking if any questions related to the category exist in the database and then saving all the questions with a valid flag set to true or false. Not unusual in a typical corporate application, but I want to test two things:

  • I can add new questions to the database with the proper valid flag.
  • If the database category already has some questions then do nothing.

After walking through the Spock mocking documentation I had a pretty good sense of the approach. In Spock it’s referred to as interactions, but it doesn’t follow the typical expect-run-verify pattern. You just verify what you need to if you need to. And given a choice I prefer not to have to verify the mock at all.

With this code I needed to mock the categoryDao which used straight JDBC and made calls to the real database. That meant I needed a way to verify that the questions were added correctly with calls to the categoryDao. Hence I needed the power of an actual mock and not just a stub class.

The first test would show that I could save new questions in a category to the database:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def "should only insert new default questions"() {
  given:
  def question1 = new Question(defaultQuestion: true)
  def question2 = new Question(defaultQuestion: false)
  def category = new Category(questions: [question1, question2])

  CategoryDao dao = Mock()
  dao.getCategory(_) >> new Category()

  CategoryService service = new CategoryService()
  service.setCategoryDao(dao)

  when:
  service.addDefaultQuestions(category)

  then:
  1 * dao.addQuestion(_, true)
  1 * dao.addQuestion(_, false)

}

So the steps are:

  1. Setup a Category object with two questions.
  2. Create a mock dao.
  3. Define a method and its default return value on the mock DAO.
    1. We define arguments to getCategory() with a wildcard operator the underscore standing in for an id.
    2. Then with the right shift operator (») we define that we will return a newly created Category object.
  4. Inject the mock into the service class we’re testing.
  5. Finally, we make verifications on the addQuestion() method by just stating the number of times we expect the method to be called with a given set of arguments, again reusing the wildcard underscore character.

You can even specify the particular order you expect by breaking the verifications into separate then: blocks. For this example it wouldn’t matter on the order, but in case it did the last when then block would change to:

1
2
3
4
5
6
7
8
when:
  service.addDefaultQuestions(category)

  then:
  1 * dao.addQuestion(_, true)

  then:
  1 * dao.addQuestion(_, false)
And to round out testing the legacy Java code we need to test the negative example where it should do nothing if there are already questions in the database for the given category.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 def "should add no questions if questions are already in database"() {
    given:
    def question1 = new Question(defaultQuestion: true)
    def question2 = new Question(defaultQuestion: false)

    CategoryDao dao = Mock()
    dao.getCategory(_) >> new Category(questions: [question1])

    CategoryService service = new CategoryService()
    service.setCategoryDao(dao)

    when:
    service.addDefaultQuestions(new Category(questions: [question2]))

    then:
    * dao.addQuestion(_,_)

  }
So we can test for the negative case by just verifying that addQuestion was called zero times.

Grails Unit Testing: Mocking With MetaClass Stubs

On a recent project I ran into issues with testing controllers in Grails. Starting test first, I spent some early time figuring out how much support there was out of the box for unit testing Grails domain classes and controllers. I setup Spock as a plugin and plunged in. I was dealing with a legacy database which had 100% compound primary keys so many of the findBy type operations that are well supported for controller testing are of no help. Often I found I needed to mock a call to a find or findAll with HQL syntax or a criteria call. I knew metaClass mocking could work here, but I wanted to understand better how that would impact the rest of the code after I started replacing methods on the fly. Turns out Grails unit testing has built in support for cleaning up metaClass hacking after every test with the registerMetaClass() method in GrailsUnitTestCase. Mrhaki has a good post on this. Here’s an Spock example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import grails.plugin.spock.ControllerSpec


class ContractControllerSpec extends ControllerSpec {

  def setup() {
    registerMetaClass Contract
  }

 def "validateContract() returns true for an existing contract"() {
    given:
    mockDomain(Contract)
    def contract = new Contract(division: '33', unit: '99', contractNumber: 'C7777777').save(flush: true)
    controller.params.division = '33'
    controller.params.unit = '99'
    controller.params.contractNumber = 'C7777777'
    Contract.metaClass.static.find = { String query, Map namedArgs -> contract }

    when:
    controller.validateContract()

    then:
    "TRUE" == controller.response.contentAsString
  }

}

Grails has support for the same idea using mockFor(), but the syntax is much like EasyMock. The same test would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import grails.plugin.spock.ControllerSpec


class ContractControllerSpec extends ControllerSpec {

 def "validateContract() returns true for an existing contract"() {
    given:
    mockDomain(Contract)
    def contract = new Contract(division: '33', unit: '99', contractNumber: 'C7777777').save(flush: true)
    controller.params.division = '33'
    controller.params.unit = '99'
    controller.params.contractNumber = 'C7777777'

  // EasyMock like syntax
  def mockContract = mockFor(Contract)
    mockContract.demand.static.find(..5) { String query, Map namedArgs -> null }

    when:
    controller.validateContract()

    then:
    "TRUE" == controller.response.contentAsString
  }

}

For pure stubs I prefer the syntax of just using MetaClass. I often don’t care about validating the exact calls to the dependent class so I don’t really want a full mock. You don’t need a call to registerMetaClass() because mockFor() does this for you.