Rails 3.2 - RSpec - Undefined method error while running RSpec test - ruby-on-rails

I'm writing some RSpec tests for a Rails 3.2 app, and Rspec keeps crashing on this test:
describe Person do
before { #person = Person.new(names: [Factory.create(:name)], DOB: Date.today) }
subject { #person }
[:names,:DOB,:phone,:email,:address1,:address2,
:city,:state,:zip,:notes,:last_seen].each do |value|
it { should respond_to(value) }
end
it { should be_valid }
describe "when no name is present" do
#person.names = []
it {should be_invalid}
end
describe "when no DOB is present" do
#person.DOB = nil
it {should be_invalid}
end
end
When I run RSpec, I get undefined method 'names=' for nil:NilClass (NoMethodError) for this line:
#person.names = []
If I remove the no-name test, then it crashs on #person.DOB = nil
It looks like somehow, #person isn't being set before the describe block. Is there some quirk of RSpec I'm missing?
Edit: The Person model:
class Person < ActiveRecord::Base
has_and_belongs_to_many :names
validates_presence_of :DOB
end
Pretty simple. There's a names_people join table to connect Name and Person. Like I've said, I can usually access name through names=(). It's something about this one test.

Solved it. I had to use the before method again to make changes to #person. For example, I had to use this:
describe "when no name is present" do
before { #person.names = [] }
it {should be_invalid}
end
Instead of this:
describe "when no name is present" do
#person.names = []
it {should be_invalid}
end

Related

How do I write this spec in MiniTest/shoulda syntax?

I have this spec that I want to translate to MiniTest.
describe User do
subject { build(:user, provider: 'foo') }
# don't validate presence of password when provider is present
it do
should_not validate_presence_of(:password)
end
end
I tried this. I am getting an error of undefined method 'should_not' for UserTest
class UserTest < ActiveSupport::TestCase
def setup
#user = build_stubbed(:user)
end
test "responds to name" do
assert_respond_to #user, :name
end
should validate_presence_of(:password)
test "do not validate presence of password when provider is present" do
build_stubbed(:user, provider: 'foo')
should_not validate_presence_of(:password)
end
end
I want to change the context for one test, where the subject gets a provider attribute, which should disable the presence validator on the password field.
Here's the full error:
UserTest#test_presence_of_password:
NoMethodError: undefined method `should_not' for #<UserTest:0x007feaa82c1c68>
test/models/user_test.rb:45:in `block in <class:UserTest>'
I found that the better way to do this is to revert to good old MiniTest:
test "uniqueness of email with a different provider" do
email_user = create(:user, email: "foo#bar.com")
facebook_user = build_stubbed(:facebook_user, email: "foo#bar.com")
assert facebook_user.valid?, "should be valid with same email if provider is different"
end
Take a look at the minitest-rails-shoulda gem. If you use it I assume the test would look like this:
describe User do
subject { build_stubbed(:user) }
it { must validate_presence_of(:password) }
describe "when a provider is present" do
subject { build_stubbed(:user, provider: 'foo') }
it { wont validate_presence_of(:password) }
end
end

Shoulda and RSpec's before

I try to set a instance variable in a subject before testing validity of model fields. I need to set this variable, because validation is conditional (it is used only for some type of users). So I have something like this:
context "as a user" do
before(:each) do
subject = Organization.new
subject.editor = "user"
end
it { subject.should validate_presence_of :name }
end
But it doesn't work as expected:
Failure/Error: it { subject.should validate_presence_of :description }
RuntimeError:
Organization#editor attr is not set
What did i miss?
subject in your before block is a local variable. It looks like you meant to use an explicit subject:
context "as a user" do
subject { Organization.new }
before(:each) do
subject.editor = "user"
end
# usually, you don't explicitly name the subject in an `it` like this
it { should validate_presence_of :name }
end

Rspec and testing instance methods

Here is my rspec file:
require 'spec_helper'
describe Classroom, focus: true do
describe "associations" do
it { should belong_to(:user) }
end
describe "validations" do
it { should validate_presence_of(:user) }
end
describe "instance methods" do
describe "archive!" do
before(:each) do
#classroom = build_stubbed(:classroom)
end
context "when a classroom is active" do
it "should mark classroom as inactive" do
#classroom.archive!
#classroom.active.should_be == false
end
end
end
end
end
Here is my Classroom Factory:
FactoryGirl.define do
factory :classroom do
name "Hello World"
active true
trait :archive do
active false
end
end
end
When the instance method test runs above, I receive the following error: stubbed models are not allowed to access the database
I understand why this is happening (but my lack of test knowledge/being a newb to testing) but can't figure out how to stub out the model so that it doesn't hit the database
Working Rspec Tests:
require 'spec_helper'
describe Classroom, focus: true do
let(:classroom) { build(:classroom) }
describe "associations" do
it { should belong_to(:user) }
end
describe "validations" do
it { should validate_presence_of(:user) }
end
describe "instance methods" do
describe "archive!" do
context "when a classroom is active" do
it "should mark classroom as inactive" do
classroom.archive!
classroom.active == false
end
end
end
end
end
Your archive! method is trying to save the model to the database. And since you created it as a stubbed model, it doesn't know how to do this. You have 2 possible solutions for this:
Change your method to archive, don't save it to the database, and call that method in your spec instead.
Don't use a stubbed model in your test.
Thoughtbot provides a good example of stubbing dependencies here. The subject under test (OrderProcessor) is a bona fide object, while the items passed through it are stubbed for efficiency.

Why my model is valid ? It shoud not

I try to practice to making some tests using Rspec and I have a weird comportment. When I try to have an invalid model to follow the Red/Green/Refactor cycle, Rspec doesn't see any error.
I want to ensure release can't have an anterior date.
My model
class Release < ActiveRecord::Base
belongs_to :game
belongs_to :platform
attr_accessible :date
validates :date, presence: true
end
My spec file
require 'spec_helper'
describe Release do
before {#release = Release.new(date: Time.new(2001,2,3))}
it{should respond_to :date}
it{should respond_to :game}
it{should respond_to :platform}
describe "when date is not present" do
before {#release.date = nil}
it {should_not be_valid}
end
describe "when date is anterior" do
before {#release.date = Time.now.prev_month}
it {should_not be_valid}
end
end
My output
.....
Finished in 0.04037 seconds
5 examples, 0 failures
Any idea ?
When you write it { should_not be_valid } you seem to think the receiver is #release (how would rspec know that?), but by default the implicit object is an instance of the class being described:
https://www.relishapp.com/rspec/rspec-core/docs/subject/implicit-receiver
Use subject { some_object } for a explicit subject or it { #release.should_not be_valid }.
More on this:
http://blog.davidchelimsky.net/2012/05/13/spec-smell-explicit-use-of-subject/
Try:
it { #release.should_not be_valid}
instead.

rails + rspec : Staying DRY when testing validations

Ok say I have the following model:
class Country < ActiveRecord::Base
validates_presence_of :name
validates_presence_of :code
end
I'm doing the rspec unit tests for those validations. They look like this:
it "should be invalid without a name" do
country = Country.new(#valid_attributes.except(:name))
country.should_not be_valid
country.errors.on(:name).should == "can't be blank"
country.name = #valid_attributes[:name]
country.should be_valid
end
it "should be invalid without a code" do
country = Country.new(#valid_attributes.except(:code))
country.should_not be_valid
country.errors.on(:code).should == "can't be blank"
country.code = #valid_attributes[:code]
country.should be_valid
end
This doesn't look quite DRY. Is there any gem or plugin that automates this kind of stuff?
I'd like to get something along these lines:
it "should be invalid without a name" do
test_presence_validation :name
end
it "should be invalid without a code" do
test_presence_validation :code
end
There are remarkable for that : http://github.com/carlosbrando/remarkable
After you can do
it { should validate_presence_of :name }
If you're using factory_girl, you can do:
it "should be invalid without a name" do
FactoryGirl.build(:country, name: nil).should_not be_valid
end
One suggestion... don't use the keyword "should" on every spec.
Instead, write: "is invalid without a name"
Try also accept_values_for gem.
It allows to do something like this:
describe User do
subject { User.new(#valid_attributes)}
it { should accept_values_for(:email, "john#example.com", "lambda#gusiev.com") }
it { should_not accept_values_for(:email, "invalid", nil, "a#b", "john#.com") }
end

Resources