What is wrong with this test?

#automated-test, #dev, #ruby

I’ll write it using plain Ruby, but I took this from a Ruby on Rails project.


What if you have some test like this:

describe User do
  it "should upcase its own name" do
    user = User.new
    user.name = "alice"
    user.upcase_name!
    expect(user.name).to eq "ALICE"
  end
end

What do you thing is wrong with it?

What if I show you this:

describe User do
  context "upcase_name!" do
    subject { User.new }
    before { subject.name = "alice" }

    it do
      expect { subject.upcase_name! }.to change { subject.name }.to("ALICE")
    end
  end
end

Is it better? Is it more difficult to read?

Feel free to comment below about all this, I will just add somethings:

Always have a subject

It is expected that all test case (aka, it) have a subject.

It is the main reason for this test. It is your target.

The first thing when I look to a test to understand it is looking for a target.

If your subject does not use the standard new/initialize create it using a subject { } block. It will be a way easier to read.

Your subject must be the same type of your top describe

Let’s say that your describe is describe User, you are supposed to test a User class or one instance. Don’t mess with this thing.

Try to find the behavior of your code

Ok, ok, ok, let’s not talk about TDD vs BDD, Test::Unit vs RSpec. Keep reading.

The behavior of your code is:

When you call upcase_name! some change happens to user’s name

So, write it in your test. Keep reading.

If you have this code:

def name=(name)
  @name = name.upcase
end

And (I don’t know why) also you have upcase_name! you need two tests.

With this code, the rewritten example will fail, because in my test I explicitly tell that it changes only when I call upcase_name!.

With this name= method it is expected to have something like this:

describe User do
  it "should always store name as upcase" do
    subject.name = "alice"
    expect(subject.name).to eq "ALICE"
  end
end

Bonus

Take a look at the output of rspec --format documentation:

$ rspec spec/foo_spec.rb --format documentation

User
  should upcase its own name
  #upcase_name!
    should change `subject.name` to "ALICE"
  should always store name as upcase

Finished in 0.02947 seconds (files took 0.16243 seconds to load)
3 examples, 0 failures