Search code examples
rubytestingrspecrspec2rspec3

Testing method that needs to sort hash by value in RSpec


I am trying to test my method that takes a hash and re-orders it. I currently have:

def sort_views 
    help = view_counter.sort_by { |route, length| length }.reverse.to_h
    p help         #just so I can see the output in the test
  end

Then for my test I have:

describe "#sort_views" do
    let(:result) do {
      "/help_page/1" => 3,
      "/about/2" => 1,
      "/contact" => 1,
      "/home" => 1,
      "/index" => 2,
    }     end
    it "then sorts them via the view count" do
      expect(subject.sort_views).to be(result)
    end
  end

My issue is that the test passes.... However, I purposely have the order wrong at the moment in the result. Yet the p help in the method CORRECTLY re-orders it, so the output is actually different. I have tried eq and eql but I believe they just test structure? I know be and equal won't work...

For context my p help outputs: {"/help_page/1"=>3, "/index"=>2, "/about/2"=>1, "/home"=>1, "/contact"=>1} when the test is run.

So is there a way for me to say test the order of the result hash in my test too without calling .sort_by { |route, length| length }.reverse.to_h on my result variable as well??


Solution

  • That's because the hashes are the same, see this post. Hashes don't really have a concept of order, when you call the sort_by method it is converting the data to an array, ordering the array, and then returning an array. If you are converting the array to a hash you will lose the order essentially.

    If you care about the order here, remove the to_h and just deal with the data as an array instead. Then your tests should work.

    You can use .to_a in the test, and you don't need reverse in the sort.

    view_counter.sort_by { |route, length| -length }
    
    let(:result) do
      {
        "/help_page/1" => 3,
        "/about/2" => 1,
        "/contact" => 1,
        "/home" => 1,
        "/index" => 2,
      }.to_a
    end