I wrote this test:
test "email validation should accept valid address" do
valid_addresses = %w[user#eee.com R_RDD#adf.com user#gmail.com hi12#hi.co a]
valid_addresses.each do |e|
#chef.email = e
assert #chef.valid?, '#{e.inspect} should be valid'
end
end
When I do rake test, the message when fail is
1) Failure:
ChefTest#test_email_validation_should_accept_valid_address [/home/ubuntu/workspace/test/models/chef_test.rb:56]:
#{e.inspect} should be valid
20 runs, 23 assertions, 1 failures, 0 errors, 0 skips
Instead of whatever |e| should be...
I want to see something like "a" should be a valid like a more descriptive message to see the variable and inspect method value.
Pleas help.
You need to use string interpolation. Which can be made using "", not ''.
assert #chef.valid?, "'#{e.inspect}' should be valid"
You don't need e.inspect, only e is enough. Like:
assert #chef.valid?, "'#{e}' should be valid"
One more suggestion is, you can use instance of the class ActiveModel::Errors containing all errors :
assert #chef.valid?, #chef.errors[:email]
Related
In Model
validates :max_panels, :if => :depot?, :numericality => true
I am writing an rspec for the above validation and found something confusing
it { should validate_numericality_of(:max_panels) if :depot? }
When ran this test case got error like
1) Site spec for valid sites - Validations
Failure/Error: it { should validate_numericality_of(:max_panels) if :depot? }
Expected errors to include "is not a number" when max_panels is set to "abcd", got errors: ["format can't be blank (nil)", "illumination can't be blank (nil)", "illumination_period can't be blank (nil)", "vertical_size must be between 0.1 and 30 metres (nil)", "horizontal_size must be between 0.1 and 200 metres (nil)", "site_authorisation_id must have a valid authorisation (nil)"]
But when i added unless in my test case it got passed, Can anybody please explain me regarding it as i am new to Rspec. Also suggest how i can write the correct rspec for above validation.
it { should validate_numericality_of(:max_panels) if :depot? unless true }
Brief looking at the source of validate_numericality_of matcher shows that it doesn't contain explicit support for :if conditions. This may be handled by base matchers, but anyway, here's an alternative idea about the testing: prepare object, attempt validation and check error messages.
Something along the lines of:
describe 'numericality validation' do
subject(:instance) { described_class.new(params) }
before { instance.valid? }
context 'when depot' do
let(:params) { { max_panels: 'abcd', depot: true} }
it { expect(instance.errors.messages[:max_panels]).to eq 'is not a number' }
end
context 'when not depot' do
let(:params) { { max_panels: 'abcd', depot: false} }
it { expect(instance.errors.messages[:max_panels]).to eq nil }
end
end
unless true will never happen, so your it is likely not running the should and looks as though it passed.
unless is not rspec, that is pure ruby. You have told rspec you have a test (it), and that the should will never run. This will show as a passed test since the it did not fail.
Another part of this is to not use conditionals in your tests. They should be predictable. Don't use if or unless to determine whether or not to run assertions.
Lastly: Your error from rspec shows a list of validation errors, not of them say anything about what you're asserting. This test has multiple issues, but is flawed even in the should
Attempting to write a custom model validation and having some trouble. I'm using a regular expression to confirm that a decimal amount is validated to be in the following format:
First digit between 0 and 4
Format as "#.##" - i.e. a decimal number with precision 3 and scale 2. I want 2 digits behind the decimal.
nil values are okay
while the values are nominally numeric, I decided to give the column a data type of string, in order to make it easier to use a regular expression for comparison, without having to bother with the #to_s method. Since I won't be performing any math with the contents this seemed logical.
The regular expression has been tested on Rubular - I'm very confident with it. I've also defined the method in the ruby console, and it appears to be working fine there. I've followed the general instructions on the Rails Guides for Active Record Validations but I'm still getting validation issues that have me headscratching.
Here is the model validation for the column :bar -
class Foo < ActiveRecord::Base
validate :bar_format
def bar_format
unless :bar =~ /^([0-4]{1}\.{1}\d{2})$/ || :bar == nil
errors.add(:bar, "incorrect format")
end
end
end
The spec for Foo:
require 'rails_helper'
describe Foo, type: :model do
let(:foo) { build(:foo) }
it "has a valid factory" do
expect(foo).to be_valid
end
describe "bar" do
it "can be nil" do
foo = create(:foo, bar: nil)
expect(foo).to be_valid
end
it "accepts a decimal value with precision 3 and scale 2" do
foo = create(:foo, bar: "3.50")
expect(foo).to be_valid
end
it "does not accept a decimal value with precision 4 and scale 3" do
expect(create(:foo, bar: "3.501")).not_to be_valid
end
end
end
All of these specs fail for validation on bar:
ActiveRecord::RecordInvalid:
Validation failed: bar incorrect format
In the ruby console I've copied the method bar_format as follows:
irb(main):074:0> def bar_format(bar)
irb(main):075:1> unless bar =~ /^([0-4]{1}\.{1}\d{2})$/ || bar == nil
irb(main):076:2> puts "incorrect format"
irb(main):077:2> end
irb(main):078:1> end
=> :bar_format
irb(main):079:0> bar_format("3.50")
=> nil
irb(main):080:0> bar_format("0.0")
incorrect format
=> nil
irb(main):081:0> bar_format("3.5")
incorrect format
=> nil
irb(main):082:0> bar_format("3.1234")
incorrect format
=> nil
irb(main):083:0> bar_format("3.00")
=> nil
The method returns nil for a correctly formatted entry, and it returns the error message for an incorrectly formatted entry.
Suspecting this has something to do with the validation logic, but as far as I can understand, validations look at the errors hash to determine if the item is valid or not. The logical structure of my validation matches the structure in the example on the Rails Guides, for custom methods.
* EDIT *
Thanks Lazarus for suggesting that I remove the colon from the :bar so it's not a symbol in the method. After doing that, most of the tests pass. However: I'm getting a weird failure on two tests that I can't understand. The code for the tests:
it "does not accept a decimal value with precision 4 and scale 3" do
expect(create(:foo, bar: "3.501")).not_to be_valid
end
it "generates an error message for an incorrect decimal value" do
foo = create(:foo, bar: "4.506")
expect(scholarship.errors.count).to eq 1
end
After turning the symbol :bar into a variable bar the other tests pass, but for these two I get:
Failure/Error: expect(create(:foo, bar: "3.501")).not_to be_valid
ActiveRecord::RecordInvalid:
Validation failed: 3 501 incorrect format
Failure/Error: foo = create(:bar, min_gpa: "4.506")
ActiveRecord::RecordInvalid:
Validation failed: 4 506 incorrect format
Any ideas why it's turning the input "3.501" to 3 501 and "4.506" to 4 506?
You use the symbol instead of the variable when checking against the regex or for nil.
unless :bar =~ /^([0-4]{1}\.{1}\d{2})$/ || :bar == nil
errors.add(:bar, "incorrect format")
end
Remove the : from the :bar
* EDIT *
It's not the specs that are failing but the model's validations upon creation. You should use build instead of create
Don't use symbol to refer an argument.
class Foo < ActiveRecord::Base
validate :bar_format
def bar_format
unless bar =~ /^([0-4]{1}\.{1}\d{2})$/ || bar == nil
errors.add(:bar, "incorrect format")
end
end
end
But if you want an regex for decimal like '1.0', '1.11', '1111.00' I advise you to use this regex:
/^\d+(\.\d{1,2})?$/
If you can to use regex for money, here is:
/^(\d{1,3}\,){0,}(\d{1,3}\.\d{1,2})$/
Good luck ^^
I'm handling a set of rspec programs and pc seems to be forcing me to convert "should" questions to "expect".
Have been able to handle most, but having problems with the following rspec setup.
Most of the other 'should' formatting involves an answer should == something and is easily converted to expect(passed_in_value).to eql(returned_value).
In this case though, I believe it is passing in a block to add to a given number, however, i and unable to just convert it to
expect(end).to eql(6) or whatever the returned value should be.
Take a look and if you have any thoughts, please pass them on
it "adds one to the value returned by the default block" do
adder do
5
end.should == 6
end
it "adds 3 to the value returned by the default block" do
adder(3) do
5
end.should == 8
end
There're several methods to do that.
result = adder(3) do
5
end
expect(result).to eq(8)
expect do
adder(3) do
5
end
end.to eq(8)
block = -> do
5
end
expect(adder 3, &block).to eq(8)
Example from comments with respond_to:
it "has a #sum method" do
[].should respond_to(:sum) #old syntax
expect([]).to respond_to(:sum) #new syntax
end
I'd like to test the validation of a model's attribute with rspec and factory_girl. The 'special' thing is, that one attribute (the name) isn't allowed to start with Numbers or special signs like %,&,$, ...
For testing this it would be great to write only one example like
it "is invalid with name starting by special character" do
["1","$","%"].each do |i|
name = i + "test"
FactoryGirl.build(:tutu, name: name).should_not be_valid
end
end
This work's for the first case but it won't return the result for the whole list. Is it possible to tell rspec not to stop on the error?
Do this instead:
["1","$","%"].each do |i|
it "is invalid with name starting by '#{i}'" do
FactoryGirl.build(:tutu, name: "#{i}test").should_not be_valid
end
end
I'm writing a controller test for a rails 3.1 app using testunit 2.4.0.
I want to assert that a certain heading does not appear on the page.
I'm using assert_select like this:
assert_select 'h1', {:text => /Key Dates/, :count => 0}
and getting the following error:
ArgumentError: assertion message must be String or Proc: <</Key Dates/>
expected but was <"Planner Maternity leave">.>(<Test::Unit::Assertions::AssertionMessage>)
I've tracked this down to the fact that assert_select calls build_message which creates an instance of AssertionMessage and passes it through to test-unit's assert. However in version 2.2 of testunit (Feb 2011) checks were added which check the type of the message passed in. These checks trigger the ArgumentError seen above.
I'm not sure whether the mistake lies with test-unit being over-strict or assert_select passing the wrong object type.
Can you advise how best to follow this up? Any work-arounds?
So, the assert_select documentation shows the following example, passing a block in:
assert_select "ol" do |elements|
elements.each do |element|
assert_select element, "li", 4
end
end
So what if you did something like...
assert_select 'h1' do |elements|
elements.length == 0 ? fail
elements.each do |element|
element.text ~= /Key Dates/ ? fail
end
end
Which basically fails if it finds the pattern OR if the number of h1 elements is zero. Obviously you would change the conditions to match what it is you're trying to test for, but does that get you any closer to what you need?
If you cannot upgrade to a bug-free version, you can just pass a third argument (the message), so you do not force the message be built:
assert_select 'h1', {:text => /Key Dates/, :count => 0}, "Unexpected Key Dates found."