Rails 3.1, RSpec: model validation validation

I started my journey with TDD in Rails and ran into a small problem regarding tests to test the model, which I seem to be unable to find. Say I have a User model,

class User < ActiveRecord::Base validates :username, :presence => true end 

and a simple test

 it "should require a username" do User.new(:username => "").should_not be_valid end 

This validates the presence check correctly, but what if I want to be more specific? For example, testing full_messages on an error object.

 it "should require a username" do user = User.create(:username => "") user.errors[:username].should ~= /can't be blank/ end 

My concern with the original attempt (using should_not be_valid) is that RSpec will not produce a descriptive error message. It simply says: โ€œExpected valid?โ€ To return false, got the true value. โ€However, the second test case has a minor flaw: it uses the create method instead of the new method to access the error object.

I would like my tests to be more specific with respect to what they are testing, but at the same time there is no need to touch the database.

Does anyone have an entrance?

+66
ruby-on-rails ruby-on-rails-3 rspec rspec-rails rspec2
Sep 24 2018-11-11T00:
source share
6 answers

First, I would like to say that you have a malicious name.

Secondly, CONGRATULATIONS that you try in TDD with ROR, I promise, as soon as you go, you will not look back.

The simplest quick and dirty solution would be to create a new valid model before each of your tests as follows:

  before(:each) do @user = User.new @user.username = "a valid username" end 

BUT, what I propose is that you have created factories for all your models, which will automatically create a valid model for you, and then you can get confused with the individual attributes and see if there is your check. I like to use FactoryGirl for this:

Basically, once you get the setup, your test will look something like this:

 it "should have valid factory" do FactoryGirl.build(:user).should be_valid end it "should require a username" do FactoryGirl.build(:user, :username => "").should_not be_valid end 

Oh, and here is a good railscast that explains all this better than me:

good luck :)




UPDATE: since version 3.0, the syntax for factory has changed. I modified my sample code to reflect this.

+90
Sep 24 '11 at 5:22
source share

An easier way to verify model validation (and much more from an active record) is to use a gem such as shoulda or remarkable .

They will allow the test as follows:

 describe User it { should validate_presence_of :name } end 
+41
01 Oct '11 at 19:00
source share

Try the following:

 it "should require a username" do user = User.create(:username => "") user.valid? user.errors.should have_key(:username) end 
+14
Jul 21 '13 at 18:29
source share

in the new rspec version, you should use expect instead, otherwise you will get a warning:

 it "should have valid factory" do expect(FactoryGirl.build(:user)).to be_valid end it "should require a username" do expect(FactoryGirl.build(:user, :username => "")).not_to be_valid end 
+2
Mar 31 '17 at 8:49
source share

I have traditionally handled error content specifications in function or query specifications. So, for example, I have a similar specification, which I will condensate below:

Function Specification Example

 before(:each) { visit_order_path } scenario 'with invalid (empty) description' , :js => :true do add_empty_task #this line is defined in my spec_helper expect(page).to have_content("can't be blank") 

So, I have my model checking if something is really there, but then my function specification, which checks the exact output of the error message. FYI, these specification features require Capybara, which can be found here .

0
Apr 03 '13 at 12:28
source share

As @nathanvda said, I would use Thoughtbot Assa Matches . With this wiggle, you can write your test as follows to check for the presence, as well as any error message.

 RSpec.describe User do describe 'User validations' do let(:message) { "I pitty da foo who dont enter a name" } it 'validates presence and message' do is_expected.to validate_presence_of(:name). with_message message end # shorthand syntax: it { is_expected.to validate_presence_of(:name).with_message message } end end 
0
Oct 05 '17 at 17:22
source share



All Articles