I have already told you that organizing your code in use cases can help you to start your projects using TDD, and also I gave you a tip on how you can organize your app in use cases.

But even if you know what your code should do, is not so obvious how you should structure your tests

Is not obvious to know…

Where should you test validations?
How granular should yours tests be?
How much should a use case function do?
What level of detail should you have in your tests?

If you have this questions…

I want to share with you a small guide that will help you to give structure to your tests, to help you build new features faster and know where to look when you have to modify existent features.

Two types of actions

The first step is to divide your use cases functions in two types

Actions that will change something, like…

  • Register user
  • Create project
  • Generate invoice
  • Register investment
  • Upload invoice

And actions that ask for something, like…

  • List all users
  • Get Project details
  • Build invoice data
  • New project form

And once that you have your actions in one of this two categories you can use this two templates…

Template for actions that change something

You can start with something like this…

module Things
  describe "Create/Change Thing" do
    it "has a form" do
      # Tests the form fields and default values.
      # (Only if you need a form to create/update the thing)
    end

    it "creates/updates a record" do
      # Tests that the record was created/updated with the right values.
    end

    it "returns success" do
      # Tests that when the thing was created successfully it returns a
      # success status.
    end

    describe "with <bad value>" do
      # When a bad value is passed

      it "does not return success" do
        # Tests that it does not returns a success status.
      end

      it "does not create/update the record" do
        # Tests that it does not create/update the record.
      end

      it "returns an error" do
        # Tests that the right error is returned in the right way.
      end
    end
  end
end

Some times you will need to write more test for more complex behaviors, here is what you can do for some common cases…

Complex default values

You can test them switching the it to describe and adding more examples.

describe "has a form" do
  example "<case 1>" do
  end

  example "<case 2>" do
  end

  #...
end

Complex calculated values when the record is created

Also you can test them switching the it to describe and adding more examples.

describe "creates a record" do
  example "<case 1>" do
  end

  example "<case 2>" do
  end

  #...
end

Different “Bad values”

To test them you can add more describe blocks.

describe "with <bad value>" do
end

describe "with <other bad value>" do
end

describe "with <other bad value>" do
end

Template for actions that ask for something

When you are asking for a single item…

You can test that you are returning just the record attributes that you will need, and the calculated values that you will need in that use case.

module Things
  describe "Get Thing" do
    it "has some attributes..." do
      # Here you can test those properties that come directly
      # from the record.
    end

    describe "<calculated value>" do
      example "<case 1>" do
      end

      example "<case 2>" do
      end

      # ...
    end

    describe "<other calculated value>" do
      example "<case 1>" do
      end

      example "<case 2>" do
      end

      # ...
    end

    #...
  end
end

When you are asking for a list of items…

You can do something very similar but you will need to add a test case to check the you are returning the right items.

module Things
  describe "Get Things" do
    it "returns all the stored <things>" do
      # Here you can check just that the count of the things
      # is right
    end

    describe "each thing..." do
      it "has some attributes..." do
        # Here you can prepare just one record and select that
        # item from the response and test the properties that come directly
        # from the record.
      end

      describe "<calculated value>" do
        example "<case 1>" do
        end

        example "<case 2>" do
        end

        # ...
      end

      describe "<other calculated value>" do
        example "<case 1>" do
        end

        example "<case 2>" do
        end

        # ...
      end

      #...
    end
  end
end

This list is not very exhaustive, but I think it can help you to get started with TDD with less frustration!

Exercise

Now, a little exercise…

Imagine you are building a blog app, and you want to be able to…

  1. Add a blog post with title and content, validating the presence of the title.

  2. List all blog posts sorted by id in a descendent way, with the id and the title.

Try write these two features using TDD and the structure from the templates… And after you have finished you can check how I would do it here.