DEV Community

loading...

RSpec: do not verify hash keys separately

vasily profile image Vasily Polovnyov ・1 min read

Sometimes I come across three separate checks in specs to make sure the hash is OK: there are keys, there are values, values have the right type.

RSpec.describe UserSerializer do
  describe "#as_json" do
    let(:user) do
      build(:user,
        first_name: "Bart",
        last_name: "Simpson",
        tel: "+777123")
    end
    let(:json) { described_class.new(user).as_json }

    it "has keys" do
      expect(json).to include(:first_name, :last_name, :tel)
    end

    it "has types" do
      expect(json[:first_name]).to be_kind_of(String)
      expect(json[:last_name]).to be_kind_of(String)
      expect(json[:tel]).to be_kind_of(String)
    end

    it "has values" do
      expect(json[:first_name]).to eq(user.first_name)
      expect(json[:last_name]).to eq(user.last_name)
      expect(json[:tel]).to eq(user.tel)
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

This spec is more confusing than helpful: when you change fields, you have to update three tests; it's hard to immediately understand what the serializer returns.

Better to use include matcher and skip type checks (it's not the responsibility of the test):

RSpec.describe UserSerializer do
  describe "#as_json" do
    it "includes first name, last name and tel" do
      user = build(:user,
        first_name: "Bart",
        last_name: "Simpson",
        tel: "+777123")
      json = described_class.new(user).as_json

      expect(json).to include(
        first_name: "Bart",
        last_name: "Simpson",
        tel: "+777123"
      )
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

pic
Editor guide
Collapse
robcodes profile image
RobCodes • Edited

What do you think about taking it one step further?

expect(json).to contain_exactly({
first_name: "Bart",
last_name: "Simpson",
tel: "+777123"}
)

Collapse
vasily profile image
Vasily Polovnyov Author

Looks awesome. Thanks!