Writing rspec for controllers with params? - ruby

I have a controller which has the following method
class <controllername> < ApplicationController
def method
if params["c"]
.....
elsif params["e"]
.....
else
.....
end
end
end
Now, I want to write rspec for the above code.
How can I write separate context for both the params and how will I mention them as a get method.

If I understand your question correctly, you can try approach like this:
RSpec.describe <controllername>, :type => :controller do
describe "GET my_method" do
context "param 'c' is provided"
get :my_method, { "c" => "sample value" }
expect(response).to have_http_status(:success)
end
context "param 'e' is provided"
get :my_method, { "e" => "sample value" }
expect(response).to have_http_status(:success)
end
end
end
Hope it puts you in proper direction.
Good luck!

Related

is there a proper way to use is_a? with an instance_double?

I have real world code which does something like:
attr_reader :response
def initialize(response)
#response = response
end
def success?
response.is_a?(Net::HTTPOK)
end
and a test:
subject { described_class.new(response) }
let(:response) { instance_double(Net::HTTPOK, :body => 'nice body!', :code => 200) }
it 'should be successful' do
expect(subject).to be_success
end
This fails because #<InstanceDouble(Net::HTTPOK) (anonymous)> is not a Net::HTTPOK
... The only way I have been able to figure out how to get around this is with quite the hack attack:
let(:response) do
instance_double(Net::HTTPOK, :body => 'nice body!', :code => 200).tap do |dbl|
class << dbl
def is_a?(arg)
instance_variable_get('#doubled_module').send(:object) == arg
end
end
end
end
I can't imagine that I am the only one in the history ruby and rspec that is testing code being that performs introspection on a test double, and therefore think there has got to be a better way to do this-- There has to be a way that is_a? just will work out the box with a double?
I would do:
let(:response) { instance_double(Net::HTTPOK, :body => 'nice body!', :code => 200) }
before { allow(response).to receive(:is_a?).with(Net::HTTPOK).and_return(true) }

Rspec to have(n).items undefined method

I'm trying to follow a guide on code.tuts and I keep getting an error.
Here is my Library spec:
require 'spec_helper'
describe Library do
before :all do
lib_arr = [
Book.new("JavaScript: The Good Parts", "Douglas Crockford", :development),
Book.new("Dont Make me Think", "Steve Krug", :usability),
]
File.open "books.yml", "w" do |f|
f.write YAML::dump lib_arr
end
end
before :each do
#lib = Library.new "books.yml"
end
describe "#new" do
context "with no parameters" do
it "has no book" do
lib = Library.new
expect(lib).to have(0).books
end
end
context "with a yaml file name parameters" do
it "has two books" do
expect(#lib).to_have(0).books
end
end
end
it "returns all the books in a given category" do
expect(#lib.get_books_in_category(:development).length).to eql 1
end
it "accepts new books" do
#lib.add_book(Book.new("Designing for the Web", "Mark Boulton", :design))
expect(#lib.get_book("Designing for the Web")).to be_an_instance_of Book
end
it "saves the library" do
books = #lib.books.map { |book| book.title}
#lib.save
lib2 = Library.new 'books.yml'
books2 = lib2.books.map { |book| book.title }
expect(books).to eql books2
end
end
I'm getting that have is undefined. I've figured out it's my lines
expect(#lib).to have(0).books
expect(lib).to have(0).books
Is my syntax out of date? I've googled and I can't find it.
The have/have_exactly, have_at_least and have_at_most matchers were removed from RSpec 3. They're now in the separate rspec-collection_matchers gem.
Or, as zishe says, instead of installing the gem, you can just use eq instead of have/have_exactly, and be >= instead of have_at_least and be <= instead of have_at_most.
Source: http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3

Mocha for same method needs to return 2 different values

Using Mocha, I'm stubbing the same method that needs to return 2 separate values. No matter what I do, it only returns 1 of the 2 values, thus 1 of my rspec tests always fail. How do I get the stub to return the correct value at the right time?
The code:
describe "#method" do
it "has something" do
hash = { "allow_sharing" => "1"}
CustomClass.stubs(:app_settings).returns(hash)
get 'method', :format => :json
JSON.parse(response.body).count.should eq(1)
end
it "does not have something" do
hash = { "allow_sharing" => "0"}
CustomClass.stubs(:app_settings).returns(hash)
get 'method', :format => :json
JSON.parse(response.body).count.should eq(0)
end
end
I also tried it this way with a before block. Still no luck.
describe "#method" do
before do
hash = { "allow_sharing" => "1"}
CustomClass.stubs(:app_settings).returns(hash)
end
it "has something" do
get 'method', :format => :json
JSON.parse(response.body).count.should eq(1)
end
# ... etc.
try using as_null_object if thats available. so for example for all lines with stubs:
CustomClass.stubs(:app_settings).returns(hash).as_null_object

How do I write functional test for this

I am pretty new to rspec. How do I write functional test for following piece of code.
class FooController < ApplicationController
 def new
#title = "Log in to Mint"
#msg = session[:msg]
session[:msg] = nil
end
end
 
How about something like this:
describe FooController do
describe "GET new" do
it "assigns 'Log in to Mint' to #title" do
get :new
assigns(:title).should == "Log in to Mint"
end
it "assigns message session to #msg" do
session[:msg] = "a message"
get :new
assigns(:msg).should == "a message"
end
it "sets message session to nil" do
get :new
session[:msg].should be_nil
end
end
end
See also: Rspec: testing assignment of instance variable

Rails 3: Custom error message in validation

I don't understand why the following is not working in Rails 3. I'm getting "undefined local variable or method `custom_message'" error.
validates :to_email, :email_format => { :message => custom_message }
def custom_message
self.to_name + "'s email is not valid"
end
I also tried using :message => :custom_message instead as was suggested in rails-validation-message-error post with no luck.
:email_format is a custom validator located in lib folder:
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
object.errors[attribute] << (options[:message] || 'is not valid')
end
end
end
Just for reference, this is what I believe is going on. The 'validates' method is a class method, i.e. MyModel.validates(). When you pass those params to 'validates' and you call 'custom_message', you're actually calling MyModel.custom_message. So you would need something like
def self.custom_message
" is not a valid email address."
end
validates :to_email, :email_format => { :message => custom_message }
with self.custom_message defined before the call to validates.
If anyone is interested I came up with the following solution to my problem:
Model:
validates :to_email, :email_format => { :name_attr => :to_name, :message => "'s email is not valid" }
lib/email_format_validator.rb:
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
error_message = if options[:message] && options[:name_attr]
object.send(options[:name_attr]).capitalize + options[:message]
elsif options[:message]
options[:message]
else
'is not valid'
end
object.errors[attribute] << error_message
end
end
end
Maybe the method "custom_message" needs to be defined above the validation.

Resources