dbird
dbird

Reputation: 336

How to test Ruby class with default parameters using RSpec

I have a class called Grid:

class Grid

  attr_reader :rows, :columns

  def initialize(rows=20, columns=20)

    @rows = rows
    @columns = columns
  end
end

I want to test that the rows and columns fields return 20 by default and return whatever integer is supplied otherwise. I don't know the best way to do this.

I "solved" this by creating two Grid instances. One has supplied values for rows and columns. The other one does not have supplied values and thus uses the default values of 20.

require_relative 'spec_helper.rb'

describe Grid do

  let(:grid) {Grid.new(15, 15)}
  let(:gridNoParameters) {Grid.new()}

  subject { grid }

  describe "#rows" do

    its(:rows) { should eq(15) }

    context "when parameter not supplied" do
      subject { gridNoParameters }

      its(:rows) { should eq(20) }
    end
  end

  describe "#columns" do
    its(:columns) { should eq(15) }

    context "when parameter not supplied" do

    subject { gridNoParameters }

    its(:columns) { should eq(20) }
  end
end

Is this the best way to test? Any help is appreciated as I am pretty new to Rspec and test driven development.

Upvotes: 2

Views: 1905

Answers (2)

jefflunt
jefflunt

Reputation: 33954

I think your approach is fine.

  • You're testing the default
  • You're testing the non-default

This particular test strikes me as a bit defensive/paranoid, but if it's critical that a test fails if/when someone accidentally changes or removes the default values, then I guess this test is fine.

Testing constructors is always a little weird to me, if all the constructor does is copy the input parameters to the instance variables. It borders on testing that the = operator in Ruby actually works, which is a bit silly. It also borders on what I call, "testing against typos," where the test will only fail if a developer makes a blindingly obvious mistake or removes a default from a method without thinking it through. The thing is, I don't believe that any amount of testing can successfully protect against sloppiness.

There are more complex situations where I might be this careful, but the class you're presenting as an example here is so simple and so straightforward that I don't think it needs anything more than this, personally.

Upvotes: 0

mswieboda
mswieboda

Reputation: 1026

I would lay out the spec like this:

describe Grid do
  context "#initialize" do
    context "with parameters" do
      let(:grid) { Grid.new(15, 15) }

      it "should use specified values" do
        expect(grid.rows).to eq 15
        expect(grid.columns).to eq 15
      end
    end

    context "without parameters" do
      let(:grid) { Grid.new }

      it "should use defaults" do
        expect(grid.rows).to eq 15
        expect(grid.columns).to eq 15
      end
    end
  end
end

Take a look at BetterSpecs for ideas how to organize specs, and to use expect notation, etc. I'm not a huge fan of using subject here, but it's up to you, as it is personal preference.

Upvotes: 3

Related Questions