1
votes

I wrote up a test that should describe the case where @user and found_user should be the same via password match. This also describes when they're different. I'm not using devise or anything, but rather building out my own authentication with has_secure_password

describe "return value of authenticate method" do
  before { @user.save }
  let(:found_user) { User.find_by(email: @user.email) }

  describe "with a valid password" do
    it { should eq found_user.authenticate(@user.password) }
  end

  describe "with an invalid password" do
    let(:user_for_invalid_password) { found_user.authenticate('invalid') }

    it { should_not eq user_for_invalid_password }
    specify { expect(user_for_invalid_password).to be_false }
  end
end

The part that's failing is with a valid password block. The error message clearly shows that password_digest isn't matching up

Here's the relavent output:

expected: password_digest: "$2a$04$cDKhuWzsZuW8Gm4t5fJjpu6rmbwh10ZAt2Yae.BO0iuD...">
got: password_digest:      "$2a$04$jwfHjoLI0RpDIAEr9SMKGOZqeH.J5ILOkzalKCYQdDW4...">

I've attempted removing the @user.save in the before block thinking that might solve it, but it didn't.

I'm not really sure why they're coming up differently or what it is that I'm doing wrong. I'm fairly new to rspec and testing in general.

I should mention that my authenticate method is working in the rails console. So I have a situation where the application code works, but the tests are failing.

Any help would be much appreciated.

My user class is here: https://gist.github.com/DavidVII/f190d1f1e114234bb7d7

Thnx!

1
Have you removed some code? I cannot see your subject block that will tell me what it is . . . that might be relevant to your error message. - Neil Slater
Here's the full user_spec.rb file if you're interesting in checking that out. gist.github.com/DavidVII/f190d1f1e114234bb7d7 - DavidVII
Thanks, I had a quick look. Not a bad start. One slightly confusing thing about the code is the mismatch between the describe and it blocks and the subject. You don't have to make describe match subject, but it really helps others to read your tests. I think however, that's a topic for a different question. As is perhaps how you are isolating the test database (your test results give me the suspicion that you may not have a completely clean test db). - Neil Slater
Indeed. I am fairly new to testing, so thanks for your advise on mismatching. I'm using postgres for my database and I feel like it's been more trouble than it's worth, but I really want the same database locally that I'm running on stage (heroku). How would I go about cleaning up my test database? - DavidVII
Okay, so this is weird. I cleaned out my database and and rebuilt it using db:schema:load and db:test:prepare. This resulted in my test passing, but if I run it again. It'll fail. I feel like I'm missing something totally obvious here, but I'm not sure what. - DavidVII

1 Answers

4
votes

Your test won't work with bcrypt password hashing (I can tell this what you are using from the form of the string), as it generates a new random salt for each password change. This is a good thing, don't alter that behaviour.

So you should not write tests that look for stored passwords being equal to known values. It is not 100% clear if you intended that in the test, or have accidentally over-simplified the test due to all the abstraction you get though using has_secure_pasword, or some other thing has led you to the current code.

Instead, your tests around password handling should be more black box, and assert that you can log in with the known password, and not login with any others (including code-breaking cases such as nils, empty strings, super-long passwords and a string which matches the hashed password).