Avoiding false-positive in tests: Don't use the same data

#automated-test, #dev, #ruby

Let’s say that I have this class to test:

require "date"

class Abc
  attr_accessor :created_at, :started_at

  def initialize(created_at = nil, started_at = nil)
    @created_at = created_at
    @started_at = started_at
  end

  def created_at_or_started_at
    @started_at || @created_at
  end
end

And I wrote this test:

describe "Abc" do
  context "when there is only created_at" do
    subject do
     Abc.new(Date.new(2018, 1, 1))
    end

    it "should return created_at" do
      expect(subject.created_at_or_started_at).to eq Date.new(2018, 1, 1)
    end
  end

  context "when there are created_at and started_at" do
    subject do
      Abc.new(Date.new(2018, 1, 1), Date.new(2018, 1, 1))
    end

    it "should return started_at" do
      expect(subject.created_at_or_started_at).to eq Date.new(2018, 1, 1)
    end
  end
end

If I replace the method created_at_or_started_at with:

  def created_at_or_started_at
    @created_at
  end

My tests will never break.

Test it by yourself, download this file and run:

$ rspec abc_spec.rb
..

Finished in 0.00476 seconds (files took 0.16384 seconds to load)
2 examples, 0 failures

Now edit the file abc_spec.rb that you just downloaded: change the second context to:

context "when there are created_at and started_at" do
  subject do
    Abc.new(Date.new(2018, 1, 1), Date.new(2018, 12, 31))
  end

  it "should return started_at" do
    expect(subject.created_at_or_started_at).to eq Date.new(2018, 12, 31)
  end
end

If you run again you will see if failing:

$ rspec abc_spec-rb 
.F

Failures:

  1) Abc when there are created_at and started_at should return started_at
     Failure/Error: expect(subject.created_at_or_started_at).to eq Date.new(2018, 12, 31)

       expected: #<Date: 2018-12-31 ((2458484j,0s,0n),+0s,2299161j)>
            got: #<Date: 2018-01-01 ((2458120j,0s,0n),+0s,2299161j)>

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -#<Date: 2018-12-31 ((2458484j,0s,0n),+0s,2299161j)>
       +#<Date: 2018-01-01 ((2458120j,0s,0n),+0s,2299161j)>

     # ./abc_spec-rb:29:in `block (3 levels) in <top (required)>'

Finished in 0.02495 seconds (files took 0.16475 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./abc_spec-rb:28 # Abc when there are created_at and started_at should return started_at

#ProTip

When I write tests with Ruby on Rails I usually write code like:

Abc.new(
  created_at: 2.days.ago,
  started_at: 2.days.from_now,
)

It is easier to write and read then Date.new(YYYY, MM, DD).