Reasonably green to testing but I was following along with a simple udemy course. I used the RSpec documentation to set up RSpec in rails to try out some testing. But I have come across an issue that for the life of me I can't figure out...
require "rails_helper"
RSpec.describe User, type: :model do
subject { described_class.new("John") }
it "initializes a name" do
expect(subject.name).to eq("John")
end
context "with no argument" do
subject { described_class.new }
it "should default to Bill as the name" do
expect(subject.name).to eq("Bill")
end
end
end
# This is my test code.
# This is my User model.
class User < ApplicationRecord
attr_reader :name
def initialize(name = "Bill")
@name = name
end
end
When I run the test it fails and says that the second test isn't returning Bill but 'nil'. However, in my User model if I remove the < Application Record it passes... Also, if I add a second parameter in the initialize, it randomly passes the default test and fails the first one returning the default name... I'm completely confused as I have been learning the testing without ApplicationRecord and that seems to be the part where it is failing. I have tried changing the subject to let(:testing){User.new} but that doesn't work. Any help seriously appreciated here as I can't seem to find it through google.
To let you know I have gem 'rspec-rails', '~> 4.0.0' included in my GemFile in the :development, :test part.
You are trying to override default initializer of a model and you doing it the wrong way. When you call new
on ActiveRecord class you need to pass a hash of parameters. To have name
field in a model you need to define it in DB schema.
Creation of an instance of User
for the first test case should look like this:
described_class.new(name: "John")
I see these ways to have a default value for an attribute:
Set it using a callback
class User < ApplicationRecord
after_initialize :set_name
private
def set_name
self.name ||= 'Bill' # Set name to Bill if it is nil
end
end
Override initialize
method.
# Please avoid this approach
class User < ApplicationRecord
def initialize(*args)
super # This will initiate default behaviour of a model
self.name ||= 'Bill'
end
end
Using attributes API as @engineersmnky suggested
class User < ApplicationRecord
attribute :name, :string, default: 'Bill'
end
I strongly recommend using a callback or attributes API approach to not broke default behaviour.
After that, your tests should pass I believe.