Why Can't I Create Active Records That Count for Something in Rspec

Rspec not changing count on create

Whenever our tests give us unexpected trouble, it's important to take a step back and re-evaluate our approach. Usually, this is an indication of some design problem, either with the code we're testing or with tests themselves.

While it sounds like using a truncation strategy has fixed this particular problem (see more on that below), i would suggest that there is more to learn from the situation.

Consider the two examples from your spec above. The only difference between them comes down to whether the code parameter is valid or not. I would argue that these examples are really testing the Group model, not the controller.

Now, if we're confident in our model test coverage, then we can take a different approach to the controller spec. From the controller's perspective, the model is a collaborator and in general, we always want to avoid indirectly testing collaborators. In this case, we can use a mock to simulate the behavior of the Group model and only test the controller behavior in isolation.

Something like this (please note the code below is incomplete and untested):

# spec/controllers/groups_controller_spec.rb
describe "#create" do

before do
# use a Test Double instead of a real model
@new_group = double(Group)
@params = { :cdb_group => 'stub_cdb_group_param', :service_id => service }
# using should_receive ensures the controller calls new correctly
Group.should_receive(:new).with(@params[:cdb_group]).and_return(@new_group)
end

context "when cancelled responding to js" do
it "renders hide_new" do
post :create, @params.merge({:button => "cancel", :format => "js"})
expect(response).to render_template('hide_new')
end
end

context "with valid params" do
before do
@new_group.should_receive(:save).and_return(true)
end

context "responding to json" # ...

context "responding to html" # ...

context "responding to xml" #...
end

context "with invalid params" do
before do
@new_group.should_receive(:save).and_return(false)
end

# ...
end

end

While the above doesn't specifically address the problem with record counts you were having, i suspect the problem may go away once you isolate your test targets correctly.

If you choose to stick with database truncation, consider using it selectively as described here.

I hope at least some of that helps :).

Rails 5 - Rspec Expect Change Count Not Working

Ok, so I figured out why it wasn't saving a new Post record. For whatever reason, the author that was supposed to be assigned to the post in the :post factory was not being created. This meant that a validation failed.

This is the :post factory I was using:

FactoryGirl.define do
factory :post do
title { Faker::Lorem.sentence }
excerpt { Faker::Lorem.paragraph }
content { Faker::Lorem.paragraph }
published false
published_at nil
post_type "article"
keywords "blog, post, key, words"
author
end
end

And this was my :author factory for my Devise Author model:

FactoryGirl.define do
factory :author do
email { Faker::Internet.email }
password "password"
password_confirmation "password"
end
end

When I was generating the attributes using the FactoryGirl

attributes_for(:post)

method, the author was not being created and therefore the author_id attribute of the post was not being set.

To fix this I had to create the author in the test then set the author_id attribute in the attributes_for method.

So my working test now looks like this:

it "saves the new Post in the database" do
author = create(:author)
expect{
process :create, method: :post, params: { post: attributes_for(:post, author_id: author.id) }
}.to change{Post.count}.by(1)
end

Although this solves my original problem, I'm not sure why the Author was not being created and associated to the Post within the attributes_for call.

How to create two user records and then verify user count is 2 in rspec?

You have attr_accessor :admin which overrides the setters and getters for the admin column. You also need to make sure that the factory contains the minimum requirement in order for you to create a record. This means that you have to use sequencing for username and add password and password_confirmation to your factory.

The final thing you need to do is to remove the attr_accessor :admin line and your tests should pass.

RSpec ActiveRecord::RecordNotFound

In your request, you're doing post :create, { appointment: { dentist_id: '1', ... } }, which means that params[:dentist_id] in your controller will be nil (notice how you're nesting dentist_id under appointment in your request params). To fix this, change @dentist = Dentist.find(params[:dentist_id]) in your controller action to @dentist = Dentist.find(params[:appointment][:dentist_id]), or change your request to post :create, { dentist_id: '1', appointment: { patient_id: '2' ... } }.

Update

You'll also need to create a Dentist record in your database before the test is run. To do that, add something like this to your test case:

describe 'POST #create' do
before { Dentist.create!(id: 1) }

it 'assigns a newly created appointment as @appointment' do
post :create, { dentist_id: '1', appointment: { patient_id: '2', appt_date: '2015-12-05 09:00:00' } }
...
end
end

Create method test keeps failing with RSpec

What is happening is when you send a request using invalid_attributes, your controller still takes the successful path through your code. You can tell from your two failures. Rendering with <[]> happens on a redirect, and object instances only have an id and created_at if they've been saved.

This would indicate that you're not validating presence of name in your Survey model:

# app/models/survey.rb
class Survey < ActiveRecord::Base
belongs_to :user

validates :name, presence: true
end

and thus it is saved successfully with a blank name.

rspec controller builds multiple records in one form

OK, I worked this out. So in the controller spec for a model that builds two models in a form.

the controller spec could should be

post :create, :account => attributes_for(:account).merge(users_attributes: [ attributes_for(:user) ])
response.should redirect_to "http://test.host/subscribe/subcode/1/user-2"

Sorry for the earlier poor description of where the error was, but hope this helps anyone else with the same issue

Rails 5 rspec - convert object to ActiveRecord Relation

The simple way to do it is to use create_list and return an ActiveRecord relation, but if I were you I'd rethink it to use stubs.

let(:array) do
list = create_list(:class_example, 4)
ClassExample.where(id: list.map(&:id))
end

Why do I receive this RSpec error when I try to create a factory?

Try adding the following line to your spec_helper.rb file:

require 'factory_girl'

Also, add these lines to your spec_helper.rb:

FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << File.expand_path('../factories', __FILE__)
FactoryGirl.find_definitions

and remove them from RSpec.configure do |config| block.

Also, make sure you defined your factories in the correct file. It should be defined in factories.rb in your test folder (spec) if you use rspec.

Update

FactoryGirl.definition_file_paths.clear
FactoryGirl.definition_file_paths << "./spec/factories"
FactoryGirl.find_definitions

These lines should go to your spec/support/factory_girl.rb file and remove them from anywhere else.

Also, add the following in your spec_helper.rb:

config.before(:all) do
FactoryGirl.reload
end

In your spec_helper.rb the Rspec.configure block should look like this:

RSpec.configure do |config|
config.mock_with :rspec
config.run_all_when_everything_filtered = true
config.filter_run :focus

config.include FactoryGirl::Syntax::Methods
end

Update

Add this to your rails_helper.rb:

require_relative 'support/factory_girl.rb'

And then it should work.



Related Topics



Leave a reply



Submit