Coder Social home page Coder Social logo

thoughtbot / shoulda-matchers Goto Github PK

View Code? Open in Web Editor NEW
3.5K 83.0 906.0 15.34 MB

Simple one-liner tests for common Rails functionality

Home Page: https://matchers.shoulda.io

License: MIT License

Ruby 97.40% HTML 0.32% CSS 0.67% JavaScript 1.03% Shell 0.58%
ruby rspec rails testing

shoulda-matchers's Introduction

Shoulda Matchers Gem Version Build Status Total Downloads Downloads

shoulda-matchers

Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test common Rails functionality that, if written by hand, would be much longer, more complex, and error-prone.

Quick links

📖 Read the documentation for the latest version. 📢 See what's changed in recent versions.

Table of contents

Getting started

RSpec

Start by including shoulda-matchers in your Gemfile:

group :test do
  gem 'shoulda-matchers', '~> 6.0'
end

Then run bundle install.

Now you need to configure the gem by telling it:

  • which matchers you want to use in your tests
  • that you're using RSpec so that it can make those matchers available in your example groups

Rails apps

If you're working on a Rails app, simply place this at the bottom of spec/rails_helper.rb (or in a support file if you so choose):

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

Non-Rails apps

If you're not working on a Rails app, but you still make use of ActiveRecord or ActiveModel in your project, you can still use this gem too! In that case, you'll want to place the following configuration at the bottom of spec/spec_helper.rb:

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec

    # Keep as many of these lines as are necessary:
    with.library :active_record
    with.library :active_model
  end
end

Minitest

If you're using our umbrella gem Shoulda, then make sure that you're using the latest version:

group :test do
  gem 'shoulda', '~> 4.0'
end

Otherwise, add shoulda-matchers to your Gemfile:

group :test do
  gem 'shoulda-matchers', '~> 6.0'
end

Then run bundle install.

Now you need to configure the gem by telling it:

  • which matchers you want to use in your tests
  • that you're using Minitest so that it can make those matchers available in your test case classes

Rails apps

If you're working on a Rails app, simply place this at the bottom of test/test_helper.rb:

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :minitest
    with.library :rails
  end
end

Non-Rails apps

If you're not working on a Rails app, but you still make use of ActiveRecord or ActiveModel in your project, you can still use this gem too! In that case, you'll want to place the following configuration at the bottom of test/test_helper.rb:

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :minitest

    # Keep as many of these lines as are necessary:
    with.library :active_record
    with.library :active_model
  end
end

Usage

Most of the matchers provided by this gem are useful in a Rails context, and as such, can be used for different parts of a Rails app:

As the name of the gem indicates, most matchers are designed to be used in "one-liner" form using the should macro, a special directive available in both RSpec and Shoulda. For instance, a model test case may look something like:

# RSpec
RSpec.describe MenuItem, type: :model do
  describe 'associations' do
    it { should belong_to(:category).class_name('MenuCategory') }
  end

  describe 'validations' do
    it { should validate_presence_of(:name) }
    it { should validate_uniqueness_of(:name).scoped_to(:category_id) }
  end
end

# Minitest (Shoulda)
class MenuItemTest < ActiveSupport::TestCase
  context 'associations' do
    should belong_to(:category).class_name('MenuCategory')
  end

  context 'validations' do
    should validate_presence_of(:name)
    should validate_uniqueness_of(:name).scoped_to(:category_id)
  end
end

See below for the full set of matchers that you can use.

On the subject of subject

For both RSpec and Shoulda, the subject is an implicit reference to the object under test, and through the use of should as demonstrated above, all of the matchers make use of subject internally when they are run. A subject is always set automatically by your test framework in any given test case; however, in certain cases it can be advantageous to override it. For instance, when testing validations in a model, it is customary to provide a valid model instead of a fresh one:

# RSpec
RSpec.describe Post, type: :model do
  describe 'validations' do
    # Here we're using FactoryBot, but you could use anything
    subject { build(:post) }

    it { should validate_presence_of(:title) }
  end
end

# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
  context 'validations' do
    subject { build(:post) }

    should validate_presence_of(:title)
  end
end

When overriding the subject in this manner, then, it's important to provide the correct object. When in doubt, provide an instance of the class under test. This is particularly necessary for controller tests, where it is easy to accidentally write something like:

RSpec.describe PostsController, type: :controller do
  describe 'GET #index' do
    subject { get :index }

    # This may work...
    it { should have_http_status(:success) }
    # ...but this will not!
    it { should permit(:title, :body).for(:post) }
  end
end

In this case, you would want to use before rather than subject:

RSpec.describe PostsController, type: :controller do
  describe 'GET #index' do
    before { get :index }

    # Notice that we have to assert have_http_status on the response here...
    it { expect(response).to have_http_status(:success) }
    # ...but we do not have to provide a subject for render_template
    it { should render_template('index') }
  end
end

Availability of RSpec matchers in example groups

Rails projects

If you're using RSpec, then you're probably familiar with the concept of example groups. Example groups can be assigned tags order to assign different behavior to different kinds of example groups. This comes into play especially when using rspec-rails, where, for instance, controller example groups, tagged with type: :controller, are written differently than request example groups, tagged with type: :request. This difference in writing style arises because rspec-rails mixes different behavior and methods into controller example groups vs. request example groups.

Relying on this behavior, Shoulda Matchers automatically makes certain matchers available in certain kinds of example groups:

  • ActiveRecord and ActiveModel matchers are available only in model example groups, i.e., those tagged with type: :model or in files located under spec/models.
  • ActionController matchers are available only in controller example groups, i.e., those tagged with type: :controller or in files located under spec/controllers.
  • The route matcher is available in routing example groups, i.e., those tagged with type: :routing or in files located under spec/routing.
  • Independent matchers are available in all example groups.

As long as you're using Rails, you don't need to worry about these details — everything should "just work".

Non-Rails projects

What if you are using ActiveModel or ActiveRecord outside of Rails, however, and you want to use model matchers in a certain example group? Then you'll need to manually include the module that holds those matchers into that example group. For instance, you might have to say:

RSpec.describe MySpecialModel do
  include Shoulda::Matchers::ActiveModel
  include Shoulda::Matchers::ActiveRecord
end

If you have a lot of similar example groups in which you need to do this, then you might find it more helpful to tag your example groups appropriately, then instruct RSpec to mix these modules into any example groups that have that tag. For instance, you could add this to your rails_helper.rb:

RSpec.configure do |config|
  config.include(Shoulda::Matchers::ActiveModel, type: :model)
  config.include(Shoulda::Matchers::ActiveRecord, type: :model)
end

And from then on, you could say:

RSpec.describe MySpecialModel, type: :model do
  # ...
end

should vs is_expected.to

In this README and throughout the documentation, you'll notice that we use the should form of RSpec's one-liner syntax over is_expected.to. Beside being the namesake of the gem itself, this is our preferred syntax as it's short and sweet. But if you prefer to use is_expected.to, you can do that too:

RSpec.describe Person, type: :model do
  it { is_expected.to validate_presence_of(:name) }
end

Matchers

Here is the full list of matchers that ship with this gem. If you need details about any of them, make sure to consult the documentation!

ActiveModel matchers

ActiveRecord matchers

ActionController matchers

  • filter_param tests parameter filtering configuration.
  • permit tests that an action places a restriction on the params hash.
  • redirect_to tests that an action redirects to a certain location.
  • render_template tests that an action renders a template.
  • render_with_layout tests that an action is rendered with a certain layout.
  • rescue_from tests usage of the rescue_from macro.
  • respond_with tests that an action responds with a certain status code.
  • route tests your routes.
  • set_session makes assertions on the session hash.
  • set_flash makes assertions on the flash hash.
  • use_after_action tests that an after_action callback is defined in your controller.
  • use_around_action tests that an around_action callback is defined in your controller.
  • use_before_action tests that a before_action callback is defined in your controller.

Routing matchers

  • route tests your routes.

Independent matchers

  • delegate_method tests that an object forwards messages to other, internal objects by way of delegation.

Extensions

Over time our community has created extensions to Shoulda Matchers. If you've created something that you want to share, please let us know!

Contributing

Have a fix for a problem you've been running into or an idea for a new feature you think would be useful? Take a look at the Contributing document for instructions on setting up the repo on your machine, understanding the codebase, and creating a good pull request.

Compatibility

Shoulda Matchers is tested and supported against Ruby 3.0+, Rails 6.1+, RSpec 3.x, and Minitest 5.x.

  • For Ruby < 2.4 and Rails < 4.1 compatibility, please use v3.1.3.
  • For Ruby < 3.0 and Rails < 6.1 compatibility, please use v4.5.1.

Versioning

Shoulda Matchers follows Semantic Versioning 2.0 as defined at https://semver.org.

Team

Shoulda Matchers is currently maintained by Pedro Paiva and Matheus Sales. Previous maintainers include Elliot Winkler, Gui Albuk, Jason Draper, Melissa Xie, Gabe Berke-Williams, Ryan McGeary, Joe Ferris, and Tammer Saleh.

Copyright/License

Shoulda Matchers is copyright © Tammer Saleh and thoughtbot, inc. It is free and opensource software and may be redistributed under the terms specified in the LICENSE file.

About thoughtbot

thoughtbot

This repo is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software! See our other projects. We are available for hire.

shoulda-matchers's People

Contributors

boone avatar dependabot-preview[bot] avatar derekprior avatar drapergeek avatar george-carlin avatar github-actions[bot] avatar guialbuk avatar jferris avatar joshuaclayton avatar kapilsachdev avatar matsales28 avatar maurogeorge avatar mcmire avatar mdaubs avatar mike-burns avatar mjankowski avatar mxie avatar readeharris avatar rmm5t avatar seanpdoyle avatar sferik avatar sikachu avatar sweed avatar technicalpickles avatar thechrisoshow avatar untidy-hair avatar vjt avatar vsppedro avatar webmat avatar wingrunr21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shoulda-matchers's Issues

passing attributes to matchers like validate_uniqueness_of

Hey, what do you think about to add ability to pass attributes to matchers like validate_uniqueness_of and so on?

it { should validate_uniqueness_of(:name) }
it { should validate_uniqueness_of(:email) }
it { should validate_uniqueness_of(:phone) }

vs

it { should validate_uniqueness_of(:name, :email, :phone) }

active_record serialize_matcher: undefined method 'serialize'

Hi there,

I was trying to use the serialize_matcher on a AR model, but I always get this error when running the spec:

Failure/Error: it { should serialize(:event_ids).as(Array) }
NoMethodError:
  undefined method `serialize' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000003d22a50>

it works if I write test without using the matcher, like this:

it "has event_ids as a serialized Array" do
  subject.serialized_attributes.keys.should include('event_ids')
  subject.serialized_attributes['event_ids'].object_class.should == Array
end

Can't run tests

I've forked the project to had "reply_to" to have_sent_email matcher but I can't run tests :

MBA-Raphael:shoulda-matchers raphaelemourgeon$ rspec spec/shoulda/action_mailer/have_sent_email_spec.rb 
/Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in `require': cannot load such file -- rspec (LoadError)
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in `block in require'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:236:in `load_dependency'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in `require'
from /Users/raphaelemourgeon/Tests/shoulda-matchers/spec/spec_helper.rb:10:in `<top (required)>'
from /Users/raphaelemourgeon/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/raphaelemourgeon/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/raphaelemourgeon/Tests/shoulda-matchers/spec/shoulda/action_mailer/have_sent_email_spec.rb:1:in `<top (required)>'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/configuration.rb:698:in `load'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/configuration.rb:698:in `block in load_spec_files'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/configuration.rb:698:in `map'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/configuration.rb:698:in `load_spec_files'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/command_line.rb:22:in `run'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:80:in `run_in_process'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:69:in `run'
from /Users/raphaelemourgeon/.rvm/gems/ruby-1.9.3-p0@global/gems/rspec-core-2.8.0/lib/rspec/core/runner.rb:10:in `block in autorun'

I can load rspec in irb :

MBA-Raphael:shoulda-matchers raphaelemourgeon$ irb
ruby-1.9.3-p0 :001 > require 'rspec'
 => true 

Thanks for your help.

Let Active{Record,Model} handle generating messages for tests

Instead of trying to mimic the behavior of ActiveRecord/ActiveModel error generation with I18n, just let the model being tested provide the default message for comparison.

generate_message has been present in ActiveRecord since 2.2.2. It has since been extracted to ActiveModel.

var in setup drops his value

Hi!
I have a strange problem with @vars in functional tests with shoulda

require 'test_helper'

class ItemsControllerTest < ActionController::TestCase
  context "getting index" do
    setup do
      @item = Factory(:item, Titulo: 'Fe en el Caos, Darren Aranofskky')
      get :index
    end
    should assign_to(:items).with([@item])
    # ...
  end
end

@item loses his value in with([@item]) like it was nil:

Failure: Expected action to assign [nil] for items, but got [<item Id_item: 51, Id_Seccion: 1774, Id_Usuario: 2146768286...>]
test: getting index should assign @Items. (itemsControllerTest)

Add hot sauce to validate_uniqueness_of

validate_uniqueness_of is the only matcher that requires an entry to exist in the data before before it can run. We can prevent this is we create the entry before hand, passing only an attribute in to the field that we're checking and just skipping validations on the model.

Something like this:
@model.new(:field => 'item1').save(:validate => false)

The second entry should still use the proper validations and fail if the validation is not set up.

I'm going to try and create a pull request for this, just wanted to get the idea down.

[Feature Request] Allow factories use in validate_uniqueness_of

Hi,

This is a feature request but I wasn't sure how to mark it as such with the Issue system. The basic idea is that once I'm using a factory system (factory_girl, machinist, etc.) its kinda silly that I'd have to write code per time I want to validate_uniqueness_of to create an object when I have a centralized definition of how to create objects. Ergo, it seems like it'd be pretty simple to allow validate_uniqueness_of to check for some type of factory system configuration (i.e. Should.factory_type = :factory_girl) and if set then try to use that factory system to create an object before executing the test.

I've implemented this specifically for factory_girl in my code base but since I'm in rails 2.3.x land still I didn't figure it was worth submitting a patch on the 2.11.3 branch of shoulda, especially since the matchers moved out of the main gem, ergo the reason I opened this issue instead. When I make it to the latest branch of code I'm sure I'll patch that too, at which time I can submit a patch with tests and such, but in the meantime I thought I'd record the feature request, and include my current code in case anyone wants to a) use it themselves, or b) do the patch before I get to it. Here's the current helper code I added:

module Shoulda
  module ActiveRecord
    module Matchers
      module ValidateUniquenessOfMatcherWithFactoryGirl
        def self.included(base)
          base.class_eval do
            alias_method_chain :matches?, :factory_girl
          end
        end

        # Use the subject to create a factory so that this passes correctly
        def matches_with_factory_girl?(subject)
          factory_name = (@factory_name || subject.class.to_s.underscore).to_sym
          # TODO Throw a better message if the factory isn't defined, i.e. tell them to define one
          Factory(factory_name)
          matches_without_factory_girl?(subject)
        end

        # Allows specifying a factory for use with validate_uniqueness_of
        #   it {should validate_uniqueness_of(:foo).with_factory(:foo_in_special_state)        
        def with_factory(factory_name)
          @factory_name = factory_name
          self
        end
      end
    end
  end
end

Shoulda::ActiveRecord::Matchers::ValidateUniquenessOfMatcher.send(:include, 
  Shoulda::ActiveRecord::Matchers::ValidateUniquenessOfMatcherWithFactoryGirl)

Thanks,
\Peter

There is no file /test/README

CONTRIBUTION_GUIDELINES.rdoc:

* Contributions without tests won't be accepted.  The file <tt>/test/README</tt> explains the testing system pretty thoroughly.

assign_to has an error message that doesn't seem accurate.

Hi I'm writing the following test with rspec and shoulda in a rails 3 project.

The Test

require 'spec_helper'

describe PhotosController do

  describe "GET 'new'" do
    context "you have authorization" do
      before do 
        @controller.stub(:authorize!)
      end

      context "given a place" do
        before do
          @place = stub_model(Place)
          Place.stub(:find).and_return(@place)

          get :new, :place_id => @place.id
        end

        it{ should respond_with(:success)}
        it{ should assign_to(:photo).with(@place.photos.build)}
        it{ should render_template(:new)}
        it{ should_not set_the_flash}
      end
    end
  end
end

The Controller

  def new
    @photo = @place.photos.build
  end

The error message

.F..

Failures:

  1) PhotosController GET 'new' you have authorization given a place 
     Failure/Error: it{ should assign_to(:photo).with(@place.photos.build)}
       Expected action to assign #<Photo id: nil, position: nil, name: nil, copyright: nil, image: nil, created_at: nil, updated_at: nil, place_id: 1002, width: nil, height: nil> for photo, but got #<Photo id: nil, position: nil, name: nil, copyright: nil, image: nil, created_at: nil, updated_at: nil, place_id: 1002, width: nil, height: nil>
     # ./spec/controllers/photos_controller_spec.rb:20:in `block (5 levels) in <top (required)>'

Finished in 0.48865 seconds
4 examples, 1 failure

Failed examples:

rspec ./spec/controllers/photos_controller_spec.rb:20 # PhotosController GET 'new' you have authorization given a place 

As you can see, the Photo objects are both identical (unless I missed something). How i'm not entirely sure what the issue with my test is, however I felt like this error message isn't properly displaying what the problem is. It felt a little miss leading. Hopefully this can be marked as a small bug or something to be fixed in the future as I'm sure there are more pressing bugs to squash.

Does this seem weird to anyone?

AssignToMatcher does not seem to instantiate RSpec subject?

Very simple controller and test:

  def index
    @locations = 'test'
  end

describe 'GET "index"' do
    subject { get :index }
    it { should assign_to(:locations) }
  end
end

Always returns 'Expected action to assign a value for @Locations'.

If I put a debugger inside the it block, @controller.instance_variables is incomplete, but if I manually call get :index and then check @controller.instance_variables, @locations is set and the test will pass.

HaveSentEmailMatcher fails when multiple emails are delivered at once

The recent refactor of HaveSentEmail broke the scenario where multiple emails delivered at the same time could be tested with the matcher. Right now, unless all delivered emails match the criteria, the matcher fails, but the matcher should really only fail if none of the delivered emails match the criteria.

(I'm looking into fixing this now)

using validate_presence_of and validate_uniqueness_of with i18n raise error

It gives error
Failure/Error: it { should validate_uniqueness_of(:scheme_id).scoped_to(:designation_id) }
Expected errors to include "%{model} is already exist" when scheme_id is set to 1732, got errors: ["scheme_id Designations scheme is already exist (1732)", "scheme_id Sale Scheme Designations scheme is already exist (1732)", "scheme_type Designations scheme is already exist (3)"]

validate_uniqueness_of expects has been taken, receives is taken

Any knowledge of this weirdness?

Failure/Error: it { should validate_uniqueness_of(:index) }
Expected errors to include "has already been taken" when index is set to "OSE", got errors: ["calendar can't be blank (nil)", "post_trade_at can't be blank (nil)", "index is already taken ("OSE")"]

As seen, index taken is reported, but the expectation tests for a different error string, or at least so it says.

rails 3.2
shoulda-matchers 1.1.0

Use the modern thoughtbot style.

We have trailing whitespace and stuff like this:

before do
  @model = define_model(:foo) do
    ....
  end
end

Current style is to do let(:model) { define_model(:foo) { ... } } instead.

There's other stuff too, I'm sure.

has_many and has_one tests fail when the reverse association has a nonstandard name

The foreign_key method returns an incorrect column name when a corresponding belongs_to uses a nonstandard foreign key name.

An example:

class User < ActiveRecord::Base
  has_many :posts, :inverse_of => author
end

class Post < ActiveRecord::Base
  belongs_to :author, :inverse_of => :posts, :class_name => :User
end

describe User do
   it { should have_many(:posts) }
end

ensure_inclusion_of should have an :allow_blank

Please note, this might not make sense until something like this #70 has been implemented since checking to see if your array options are blank won't make senese unless you have array options.

So something like

   should ensure_inclusion_of(:foo).in_array(['bar', 'zap', 'cap']), :allow_blank => true

another possible option would be

should ensure_inclusion_of(:foo).in_array(['bar', 'zap', 'cap'], :allow_blank => true)

accept_nested_attributes_for matcher

Would you guys consider an accept_nested_attributes_for matcher?

Given the following classes:

class Post < ActiveRecord::Base
  has_many :comments
  accepts_nested_attributes_for :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

Support the following test case:

describe Post do
  it { should accept_nested_attributes_for(:comments) }
end

Implementation could be as simple as testing for the existence of a #comments_attributes= method. If you're into it I'd be happy to send a pull request!

render_template together with rspec does not work properly

In RSpec render_template which delegates to assert_template. It supports the option :partial. Shoulda doesn't delegate to the standard rails method and therefore does not support this option.
All existent tests using this option will fail after including shoulda_matchers.

Is it a bug or a feature?

should fail if with_options is incorrect on have_db_column

Found this issue by accident.

If I misspell an option in the have_db_column test the test will still pass.

For example:

it { should have_db_column(:time_zone).of_type(:string).with_options(:defult => "Melbourne") }

Will pass even though "default" is spelt incorrectly as "defult". I stepped through the code and the with_options function only assigns if the spelling is correct, otherwise it will ignore the with_options parameters as if none had been specified.

I assume that there should be a line here that would error if an option is passed that does not match any of the standard options.

I'm fairly new to both Rails and programming and don't feel confident in doing a pull request to solve this, but hope it will help someone else do so.

Cheers.

have_sent_email add to model test?

Hi

I was wondering, would it be useful to add the ability to test if a models method sends an email? Here is my reasoning. I have an Invitation model and I would like to send out an invite which does two things. 1 sends an email 2. Updates my sent_at column so I thought it would make sense to have a public method on my invitation model called "send_invite!" that would send the invitation then update my sent_at column.

I want to create a test for that that would only send invites when the sent_at column is nil. Currently it seems like you can only test Mailers. (I keep getting this error)

     Failure/Error: it{ should have_sent_email( @invitation.email )}
     NoMethodError:
       undefined method `has_sent_email?' for #<Invitation:0x007fb2532e38f0>
     # ./spec/models/invitation_spec.rb:29:in `block (4 levels) in <top (required)>'

which makes sense however because Im testing on a model.

Anyway, does that seem right or is my logic skewed?

Allow value for multiple fields...useful?

I'm trying to figure out if I'm just doing this wrong or if this might be a useful feature:

it { should allow_value('CA').for(:school_state, :ship_state) }

instead of

it { should allow_value('CA').for(:school_state) }
it { should allow_value('CA').for(:ship_state) }

Thanks!

Add more parameters to ValidateNumericalityOfMatcher

it { should validate_numericality_of(:age).greater_than(18) }
it { should validate_numericality_of(:age).less_than(300) }
it { should validate_numericality_of(:age).greater_than_or_equal_to(18) }
it { should validate_numericality_of(:age).less_than_or_equal_to(300) }
it { should validate_numericality_of(:age).equal_to(25) }

validate_uniqueness_of breaks with factory girl

Hi I have an Invitation model that I'm testing which currently just has an email and token. My test looks kind of like this.

Model

class Invitation < ActiveRecord::Base
  #Validations 
  validates :email, :presence => true
  validates :token, :uniqueness => true

  #callback
  before_validation :generate_token

  private 

  def generate_token
    self.token = Digest::SHA1.hexdigest([Time.now, rand].join)
  end
end

Spec

require 'spec_helper'

describe Invitation do 
  describe "Validations" do 
    it{ should validate_presence_of(:email)}
    it{ FactoryGirl.create(:invitation); should validate_uniqueness_of(:token)}
  end
end

Error message

.F

Failures:

  1) Invitation Validations 
     Failure/Error: it{ FactoryGirl.create(:invitation); should validate_uniqueness_of(:token)}
       Expected errors to include "has already been taken" when token is set to nil, got errors: ["email can't be blank (nil)"]
     # ./spec/models/invitation_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.12196 seconds
2 examples, 1 failure

Failed examples:

rspec ./spec/models/invitation_spec.rb:6 # Invitation Validations 

Factory Girl defined

FactoryGirl.define do
  factory :invitation do
    sequence(:email){|n| "email#{n}@domain.com" }
    token "5m234m3m23mf3"
  end
end

As you can see, for some reason when the "uniqueness_of" matcher is called, it's trying to create an invitation without an email address. I can confirm everything works as I would like in my rails console however things are breaking in my test. I'm pretty sure this is something to do with the matchers however this could be something with factory girl but I'm still unsure.

Unless I'm missing something obvious here, am I right to presume something is broken?

Association matchers do not work on classes inherited from abstract class

Association matchers do not work on classes inherited from an abstract class. Example:

class User < ActiveRecord::Base
  self.abstract_class = true
  has_many :posts
end

class Author < User
  self.table_name = "authors"
  # ...
end

user_spec.rb

describe User do
  describe Admin do
      it { should have_many :posts } #=> Mysql2::Error: Incorrect table name '': SHOW FULL FIELDS FROM ``
  end
end

admin_spec.rb

describe Admin do
  it {should have_many :posts } #=> pass
end

It seems that the matcher is attempting to use the table name of the super class.

Use methods for failure_message instead of attr_reader

See here and here for the API. Not sure how much of this is RSpec 2.9 newness, though.

We currently use attr_reader :failure_message, :negative_failure_message and set instance variables - it'd be nice to
have those be actual methods. It'd take some refactoring though.

some error when try to validate

Hi everyone,
I have some error:
it{ should validate_numericality_of(:number) .in_range(0..100) #=>underfine method in_range it{ should validate_numericality_of(:number) Failure/Error: it{ should validate_numericality_of(:number) } Expected errors to include "is not a number" when number is set to "abcd", got errors: ["required_points can't be blank (nil)", "required_points can only be positive integer. (nil)", "required_points can't be blank (nil)", "required_points can only be positive integer. (nil)", "number can only be integer between 0 and 100. (0)", "number can only be integer between 0 and 100. (0)", "total_points can only be positive integer. (nil)", "total_points can only be positive integer. (nil)"]

IN model:
validates_uniqueness_of :number validates_presence_of :number validates_numericality_of :number, integer_only: true, within: 0..100

Help me fix this error. Thanks :D

ensure_length_of problem

Not sure if this is a newer Rails problem (I'm on 3.2.2), or if I'm using this improperly, but the ensure_length_of matcher seems to be failing a correct match due to ActiveRecord error hash format. (Possibly strict comparison in errors array?)

user_spec.rb

...
describe User do
  it { should ensure_length_of(:card_number).is_equal_to(14) }
end

test output


  1) User 
     Failure/Error: it { should ensure_length_of(:card_number).is_equal_to(14) }

       Expected errors to include "is the wrong length (should be 14 characters)" 
       when card_number is set to "xxxxxxxxxxxxxx", got errors:
       ["card_number is the wrong length (should be 14 characters) (0)"]

validate() isn't detected by shoulda

I noticed that validations created with the validate method aren't being tested by shoulda.

Here's a Gist describing the problem: https://gist.github.com/391ffb0161f30582274c

Move through the history to see how the tests fail with validate and how they pass with validates_presence|uniqueness_of

Put here in case since I'm actually just including gem 'shoulda-matchers', since I'm using RSpec.

RSpec 2.10 compatibility

I believe RSpec expects any matcher to respond to both matches? and failure_message_for_should. As shoulda matchers respond to failure_message only I have had to add the following to a support file to get RSpec to recognise shoulda matchers for associations.

require 'shoulda/matchers'

module Shoulda
  module Matchers
    module ActiveRecord
      class AssociationMatcher
        alias_method :failure_message_for_should, :failure_message
      end
    end
  end
end

I think adding an alias to make sure both methods are available should be enough to make shoulda matchers compatible with RSpec 2.10+.

An example error message you will see when running a matcher like…

describe User do
  it { should have_many(:disguises) }
end

…is as follows…

Failure/Error: it { should have_many(:disguises) }
NoMethodError:
  undefined method `has_many?' for #<User:0x007fd2f4f33210>
# ./spec/models/user_spec.rb:2:in `block (2 levels) in <top (required)>'

If you would like me to add aliases and send through a pull request including specs let me know. I'll be happy to help.

EDIT In order to get all custom matchers to work I've hacked the following to my project. It's not going to win any coding style awards, but it works for me.

require 'shoulda/matchers'

module Shoulda
  module Matchers
    [ActiveRecord, ActiveModel, ActionController, ActionMailer].each do |matchers_module|
      matchers_module.constants.each do |constant|
        if constant.to_s =~ /Matcher$/
          class_eval <<-RUBY
            class #{matchers_module}::#{constant}
              alias_method :failure_message_for_should, :failure_message
            end
          RUBY
        end
      end
    end
  end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.