Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec "count" change.by?

So I was looking at: https://rubyplus.com/articles/1491-Basic-TDD-in-Rails-Writing-Validation-Tests-for-the-Model

Just seeing techniques of testing and I saw this:

require 'rails_helper'

describe Article, type: :model do
  it 'is valid if title and description fields have value' do
    expect do
      article = Article.new(title: 'test', description: 'test')
      article.save
    end.to change{Article.count}.by(1)
  end
end

Specifically the last line: end.to change{Article.count}.by(1). From reading https://relishapp.com/rspec/rspec-expectations/v/3-7/docs/built-in-matchers/change-matcher

It says specifically:

The change matcher is used to specify that a block of code changes some mutable state. You can specify what will change using either of two forms:

Which makes sense. But were testing Article.count in the block of code which isn't actually "doing" anything (The article.save is what actually changed the Article.count so how exactly does this work? Does the test take a a look at whats in the block of code before it's ran and "prerun" it...the compare the .by(1) after?

Thanks

like image 656
msmith1114 Avatar asked May 31 '18 18:05

msmith1114


1 Answers

There are two blocks of code being executed. The block of code passed to expect, and the block of code passed to change. This is what's really happening, in pseudo-code.

difference = 1
initial_count = Article.count

article = Article.new(title: 'test', description: 'test')
article.save

final_count = Article.count

expect(final_count - initial_count).to eq(difference)

I would refactor your test to be a little easier to follow as this:

require 'rails_helper'

describe Article, type: :model do
  let(:create_article) { Article.create(title: 'test', description: 'test') }

  it 'is valid if title and description fields have value' do
    expect { create_article }.to change { Article.count }.by(1)
  end
end
like image 135
Daniel Westendorf Avatar answered Oct 29 '22 12:10

Daniel Westendorf