Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec & Custom matcher with multiple arguments

I'm trying to create a custom matcher for my tests in RoR using RSpec.

  define :be_accessible do |attributes|
    attributes = attributes.is_a?(Array) ? attributes : [attributes]
    attributes.each do |attribute|
      match do |response|
        response.class.accessible_attributes.include?(attribute)
      end
      description { "#{attribute} should be accessible" }
      failure_message_for_should { "#{attribute} should be accessible" }
      failure_message_for_should_not { "#{attribute} should not be accessible" }
    end
  end

I want to be able to write something like the following in my tests:

...
should be_accessible(:name, :surname, :description)
...

but with the matcher defined above, I must pass an array of symbols instead of symbols separated by commas otherwise the test examines only the first symbol.

Any ideas?

like image 317
Lazarus Lazaridis Avatar asked Apr 21 '13 20:04

Lazarus Lazaridis


People also ask

What is RSpec used for?

RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.

Is RSpec TDD or BDD?

RSpec is a Behavior-Driven Development tool for Ruby programmers. BDD is an approach to software development that combines Test-Driven Development, Domain Driven Design and Acceptance Test-Driven Planning. RSpec helps you do the TDD part of that equation, focusing on the documentation and design aspects of TDD.

Is RSpec used for unit testing?

RSpec is a unit test framework for the Ruby programming language. RSpec is different than traditional xUnit frameworks like JUnit because RSpec is a Behavior driven development tool.

Is RSpec a framework?

RSpec is a framework that allows us to do that. The "R" stands for Ruby, and "Spec" is short for Specification. A specification is a detailed requirement that our code should meet. Or more formally, it's an executable example that tests whether a portion of code exhibits the expected behavior in a controlled context.


1 Answers

I made it work this way :

RSpec::Matchers.define :be_accessible do |*attributes|
  match do |response|

    description { "#{attributes.inspect} be accessible" }

    attributes.each do |attribute|
      failure_message_for_should { "#{attribute} should be accessible" }
      failure_message_for_should_not { "#{attribute} should not be accessible" }

      break false unless response.class.accessible_attributes.include?(attribute)
    end
  end
end

I inverted the match and the each loop. I think this is the way Rspec expect it to be, as the block given to the match method is the one executed by Rspec abstract matcher (I guess).

By defining the block with |*attributes|, it takes the list of parameters and turn it into an Array.

So calling should be_accessible(:name, :surname, :description) will work.

By the way, if you just want to check for the existence of attributes, a simple

should respond_to(:name, :surname, :description)

works as well. But it does not looks like for mass-assignement aspect.

like image 179
Saaman Avatar answered Sep 30 '22 17:09

Saaman