rspec vote validations error: must pass hash as an argument - ruby

I am trying to write a spec code for a vote_spec model. Not sure what exactly it is I'm doing wrong. I think it may be in the first #vote attribute in the before block.
This is how the validations should work:
Console
v = Vote.new(value: 1)
v.valid? #=> true
v2 = Vote.new(value: -1)
v2.valid? #=> true
v3 = Vote.new(value: 2)
v3.valid? #=> false
This is the error:
Failure/Error: #vote = Vote.create(:post_id)
ArgumentError:
When assigning attributes, you must pass a hash as an argument.
This is my vote_spec.rb
require 'rails_helper'
describe Vote do
describe "validations" do
before do
#vote = Vote.create(:post_id)
#vote.create(value: 1)
#vote.create(value: -1)
end
describe "first_validation" do
it "only allows -1 as a value" do
expect(#vote.first_validation).to eq(-1)
end
end
describe "second_validation" do
it "only allows 1 as a value" do
expect(#vote.second_validation).to eq(1)
end
end
end
end

If you want to test validation, maybe you could do something like this:
describe "validations" do
it 'is valid if the value is 1' do
expect(Vote.new(value: 1)).to be_valid
end
it 'is valid if the value is -1' do
expect(Vote.new(value: -1)).to be_valid
end
[-3, 0, 4].each do |invalid_value|
it "is not valid if the value is #{invalid_value}" do
expect(Vote.new(value: invalid_value)).not_to be_valid
end
end
end

Amanjot,
Also as Sasha mentioned in the comments. You can just continue with this below code I think
require 'rails_helper'
describe Vote do
describe "validations" do
before do
#first_vote = Vote.create(value: -1) # Vote.new(value: -1) - should try this too
#second_vote= Vote.create(value: 1) # Vote.new(value: 1) - should try this too
end
describe "first_validation" do
it "only allows -1 as a value" do
expect(#first_vote.value).to eq(-1)
end
end
describe "second_validation" do
it "only allows 1 as a value" do
expect(#second_vote.value).to eq(1)
end
end
end
Try out something like this. You would need to use the create action on the Vote model.

Related

Simplifying `if then` blocks

I have several instances of code that look like this:
if checkProperties(top_properties, payload) == false
return false
end
checkProperties has only one return for false depending on some condition:
def checkProperties(properties, to_check)
properties.each do |property|
if to_check[property.to_s].nil? or to_check[property.to_s].blank?
log_err("Something went wrong")
return false
end
end
end
However I feel this can be simplified. Is it valid to just use the following?
return false unless checkProperties(top_properties, payload)
Any other suggestions?
Don’t return from blocks in the first place. Use break instead:
def checkProperties(properties, to_check)
properties.each_with_object(true) do |property, _|
if to_check[property.to_s].to_s.empty?
log_err("Something went wrong")
break false
end
end
end
or use any? and/or all?:
def checkProperties(properties, to_check)
(!properties.any? { |p| to_check[p.to_s].to_s.empty? }).tap do |good|
log_err("Something went wrong") unless good
end
end
To explicitly show what property was missing, use Enumerable#find:
def empty_property?(properties, to_check)
!!(properties.find { |p| to_check[p.to_s].to_s.empty? }.tap do |prop|
log_err("Property #{prop.inspect} was missing") unless prop.nil?
end)
end
I also took a liberty to renamed a method to follow Ruby naming convention (snake case with a question mark on the end for methods returning true/false.)
Double bang trick is needed to produce true/false out of possible values returned from find: the missing property or nil.
You can check with all? enumerator. This will return true only if all has values below:
def checkProperties(properties, to_check)
properties.all? { |p| to_check[p.to_s] && !to_check[p.to_s].blank? }
end
If any of the property in to_check is nil/absent, all? will return false and stop iterating from there.
Any other suggestions?
A custom error class would work:
class PropertyError < StandardError
end
You could raise it when encountering a missing property:
def check_properties(properties, to_check)
properties.each do |property|
raise PropertyError if to_check[property.to_s].blank?
end
end
This would eliminate the need for conditionals and explicit returns, you'd just have to call:
def foo
check_properties(top_properties, payload)
# do something with top_properties / payload
end
And somewhere "above" you could handle the logging:
begin
foo
rescue PropertyError
log_err 'Something went wrong'
end
Of course, you can also store the missing property's name or other information in the exception to provide a more meaningful error / log message.

New to ruby and trying to fix the error from rspec

Hi I need to know how to do the following
rspec code:
2) WebServer::Htaccess#authorized? for valid-user with valid credentials returns true
Failure/Error: expect(htaccess_valid_user.authorized?(encrypted_string)).to be_true
ArgumentError:
wrong number of arguments calling `authorized?` (1 for 0)
# ./spec/lib/config/htaccess_spec.rb:82:in `(root)'
# ./spec/lib/config/htaccess_spec.rb:44:in `stub_htpwd_file'
# ./spec/lib/config/htaccess_spec.rb:41:in `stub_htpwd_file'
# ./spec/lib/config/htaccess_spec.rb:40:in `stub_htpwd_file'
# ./spec/lib/config/htaccess_spec.rb:81:in `(root)'
Here is the spec.rb file
let(:htaccess_valid_user) { WebServer::Htaccess.new(valid_user_content) }
let(:htaccess_user) { WebServer::Htaccess.new(user_content) }
describe '#authorized?' do
context 'for valid-user' do
context 'with valid credentials' do
it 'returns true' do
stub_htpwd_file do
expect(htaccess_valid_user.authorized?(encrypted_string)).to be_true
end
end
end
context 'with invalid credentials' do
it 'returns false' do
stub_htpwd_file do
expect(htaccess_valid_user.authorized?(encrypted_string('bad user'))).not_to be_nil
expect(htaccess_valid_user.authorized?(encrypted_string('bad user'))).to be_false
end
end
end
end
I am new to ruby TDD, and all I have in my file right now is
def authorized?
end
I am fluent in Node.js but this is completely new to me.
Please help.
It's right there in the error message.
ArgumentError:
wrong number of arguments calling `authorized?` (1 for 0)
You've passed arguments to the authorized? method.
expect(htaccess_valid_user.authorized?(encrypted_string)).to be_true
^^^^^^^^^^^^^^^^^^
But authorized? takes no arguments.
def authorized?
end
Unlike Javascript, Ruby will check you passed in the right number of arguments. If you specify no argument list, the default is to enforce taking no arguments. Add some.
def authorized?(authorization)
end

Undefined local variable or method in Rspec test?

Here is my class
class Hero
attr_reader :strength, :health, :actions
def initialize(attr = {})
#strength = attr.fetch(:strength, 3)
#health = attr.fetch(:health, 10)
#actions = attr.fetch(:actions, {})
#dicepool = attr.fetch(:dicepool)
end
def attack(monster)
#dicepool.skill_check(strength, monster.toughness)
end
end
And these are my tests
require 'spec_helper'
require_relative '../../lib/hero'
describe Hero do
let(:dicepool) {double("dicepool")}
describe "def attributes" do
let(:hero){Hero.new dicepool: dicepool}
it "has default strength equal to 3" do
expect(hero.strength).to eq(3)
end
it "has default health equal to 10" do
expect(hero.health).to eq(10)
end
it "can be initialized with custom strength" do
hero = Hero.new strength: 3, dicepool: dicepool
expect(hero.strength).to eq(3)
end
it "can be initialized with custom health" do
hero = Hero.new health: 8, dicepool: dicepool
expect(hero.health).to eq(8)
end
describe "attack actions" do
let(:attack_action) {double("attack_action") }
let(:hero) {Hero.new dicepool: double("dicepool"), actions: {attack: attack_action} }
it "has attack action"
expect(hero.actions[:attack]).to eq(attack_action)
end
end
end
I keep on getting
in `block (3 levels) in ': undefined local variable or method 'hero' for
RSpec::ExampleGroups::Hero::DefAttributes::AttackActions:Class (NameError)
and I don't know why. This is my first day of writing Rspec tests so please be nice...
You have a typo in your last test, you forgot the word do:
it "has attack action" do
expect(hero.actions[:attack]).to eq(attack_action)
end
Everything passes once added.
You are not passing a block to the it method (you missing both do and end at the end).
it "has attack action"
^^^
The correct code should look like this:
describe Hero do
let(:dicepool) {double("dicepool")}
describe "def attributes" do
let(:hero){Hero.new dicepool: dicepool}
it "has default strength equal to 3" do
expect(hero.strength).to eq(3)
end
it "has default health equal to 10" do
expect(hero.health).to eq(10)
end
it "can be initialized with custom strength" do
hero = Hero.new strength: 3, dicepool: dicepool
expect(hero.strength).to eq(3)
end
it "can be initialized with custom health" do
hero = Hero.new health: 8, dicepool: dicepool
expect(hero.health).to eq(8)
end
describe "attack actions" do
let(:attack_action) {double("attack_action") }
let(:hero) {Hero.new dicepool: double("dicepool"), actions: {attack: attack_action} }
it "has attack action" do
expect(hero.actions[:attack]).to eq(attack_action)
end
end
end
end

rspec check 'with' argument is true

I have the following rspec example:
describe "with spike" do
it "succeeds" do
a = double('whatever')
a.should_receive(:b).with(true)
a.b('not false')
end
end
How can I make with accept any non-false argument?
Just write an arbitrary message handler:
describe "with spike" do
it "succeeds" do
a = double('whatever')
a.should_receive(:b) { |x|
x.should_not be_false
}
a.b('not false')
end
end

RSpec: How do I refactor a group of tests that are repeated and the only thing that changes is the subject and expectations

I have a test suite that resembles the situation I describe with the following code. There are two contexts that define the subject. The subject is similar, the same kind of object, but with different values.
Over that subject I run two tests. One test is exactly the same for both and the other is different.
Suggest a refactor that would eliminate duplication, besides the obvious 'move the code to a method', which I don't like because it looses clarity.
require 'rspec'
describe "tests over numbers" do
context 'big numbers' do
subject { 5000 }
describe "#to_string" do
its(:to_s) {should be_a(String)}
end
describe "#+1" do
it "+1" do
sum = subject+1
sum.should == 5001
end
end
end
context 'small numbers' do
subject { 100 }
describe "#to_string" do
its(:to_s) {should be_a(String)}
end
describe "#+1" do
it "+1" do
sum = subject+1
sum.should == 101
end
end
end
end
Maybe shared examples is the way to go?
shared_example "numbers" do
describe "#to_string" do
it "should convert to a string" do
example.to_s.should be_a(String)
end
end
describe "#+1" do
it "should increment" do
sum = example+1
sum.should == example.next
end
end
end
describe "big_numbers" do
it_behaves_like "numbers" do
let(:example) { 5000 }
end
end
describe "small_numbers" do
it_behaves_like "numbers" do
let(:example) { 100 }
end
end
[5000, 100].each do |my_test|
subject { my_test }
describe "#to_string" do
its(:to_s) {should be_a(String)}
end
describe "#+1" do
it "+1" do
sum = subject+1
sum.should == my_test + 1
end
end
end

Resources