Reputation: 1344
I'm trying to test the behavior of a custom search method in my controller:
#RecordingsController
def search
# raise params.inspect
@search = params[:search]
searches = []
searches2 = []
for n in 1..5
searches << @search["date(#{n}i)"].to_i
searches2 << @search["date2(#{n}i)"].to_i
end
start_date = date_format(*searches)
end_date = date_format(*searches2)
conditions = []
conditions << "agent like '%#{@search["agent"]}%'" unless @search["agent"].blank?
conditions << "phone like '%#{@search["phone"]}%'" unless @search["phone"].blank?
conditions << "date between '#{start_date}' and '#{end_date}'"
@recordings = Recording.where(conditions.join(" AND ")).order('date ASC')
if @recordings.blank?
redirect_to("/", alert: "No results were found for this search. Please try again.")
else
render "recordings/search"
end
end
using the following layout:
#recordings_controller_spec.rb
describe RecordingsController do
describe "POST #search" do
context "with valid attributes" do
it "assigns a new search to @search" do
search = @recording_search
get :search, @recording_search
assigns(:search).should eq(search)
end
it "populates an array of recordings"
it "renders the :search view"
end
end
end
The furthest I've gotten is trying to build a hash that mimics what my params hash would be for the form
#params hash
params = {"search" => { "date_1i" => "2012", "date_2i" => "1", ... "date2_5i" => "00" } }
where date_#{n}i is the start date [year, month, day, hour, minute], and date2_#{n}i is the end date. I'm trying to follow the answer posted here, mimicking the params hash with just a regular hash. As you can see from my controller, I don't actually pass parameters to my #search method. Should I be? Or is there a way to mock a params hash in an rspec test and determine if my @search
, @recordings
, and redirect_to
/render
variables/actions are being performed? I'm already kind of testing the render/redirect in my request spec, but I'd like to fully test this method if I can.
Upvotes: 1
Views: 5436
Reputation: 19145
You should be able to generate a controller spec that GETs the search action with a given set of parameters. This will cause those parameters to be available to the params hash. You can then verify how the search is constructed and which results are returned.
describe RecordingsController do
describe '#search' do
it 'should return results' do
get :search, "search" => { "date_1i" => "2012", "date_2i" => "1", ... "date2_5i" => "00" }
response.should be_ok
@recordings.map(&:name).should == ['expected1', 'expected2']
end
end
end
This example executes a search with some search criteria as query parameters, verifies the response is successful (http 200 status), and then extracts the list of recordings returned and tries to map them to a list of friendly recording names (you can use any key on this model) to compare them to an expected list of results.
It'll be easier to write/test this code if you separate the concerns in this controller - you could write a helper that processes the query parameters and builds a search filter, which it then passes to the Recording model in the controller:
class RecordingController
def search
@search_filter = SearchFilter.for_params(params[:search])
@recordings = Recording.where(@search_filter).order('date ASC')
render "recordings/search"
end
end
class SearchFilter
# Return search params as a hash for given request params hash
def self.for_params(params)
...
end
end
This would let you write a unit test for the logic that generates search filters and only verify that the controller is doing the more simple operation of passing information between the search logic and the Recording model collection. I'd also recommend moving your logic about displaying empty results into the view on the results page and out of the controller.
Upvotes: 2