Changes to objects not being caught in RSpec tests? Use reload.

Kenshin6 | almost 2 years ago.
Large rspec
  • There are already a few great articles out there on the web discussing this topic, but I wanted to write this in the hope that I could save someone else from the hours of confusion and searching that I went through before finding them.

    The set up

    I was writing a test for a rake task running on a nightly cron that updated the :corrections_count column on a correction_reports table.

    expect {
      @rake[task].invoke
    }.to change {report.corrections_count}.by(1)
    

    The issue was, this test always returned red and report.corrections_count remained 0. I double checked my rake code and everything checked out. I ran a few local tests and confirmed the column was updating. I added some puts inside the rake to prove that the column was being updated in the db. But :corrections_count refused to update back in the test.

    Reload objects in tests after making changes to the db

    The solution was to reload the object after running the rake to pull out the updated information from the db. When defining the report with RSpec's let, you're creating an object and setting it equal to the information pulled from the db before your test block is run. So what I'd actually been testing was whether the object loaded into memory had changed, which it hadn't. To check whether the information in the database had been updated, you need to reload your object.

    expect {
      @rake[task].invoke
    }.to change {report.reload.corrections_count}.by(1)
    

    Green baby green.