Funktional
A Rails testing framework with a railsy syntax
Install
-
Via the gem
gem install funktional
-
With braid
braid add git://github.com/brentgreeff/funktional.git -p
-
add a setup line to ‘test/test_helper.rb’
class ActiveSupport::TestCase setup :funktional end
Done!
For extra flavour, add:
* should_pricot (Hpricot matchers in Test::Unit)
* hash_factory (Super simple factories for your tests)
* matchy (RSpec matchers in Test::Unit)
Contexts
Contexts, Don’t Repeat Yourself, share common setup steps between your tests.
context "On a hot summer day" do
before { day :hot }
context "in the middle of July" do
before { Time.now = 'July 15' }
should "be on the beach" do
assert_equal 'beach', @me.location
end
should "be drinking lemonade" do
assert_equal 'lemonade', @me.drinking
end
end
end
Unit tests
Define domain logic through validations.
-
Start off with a valid instance
context "A Company" do setup { @company = create_company } should "respond to fax no" do @company.should_respond_to :fax_no end should "require a name" do @company.should_require_a :name, 'please enter the name' end should "require an address" do @company.should_require_an :address, 'please enter the address' end should "not allow creative accounting" do @company.creative_accounting = true @company.should_have_invalid :books, 'no creative accounting please' end should "not require a telephone no if an address is present" do @company.address = an_address @company.should_not_require_a :telephone_no end should "not have a name longer than 80 characters" do @company.name = 81.random_characters @company.should_have_invalid :name, 'max is 80' # random_characters is a small useful helper method. end end
should "send email" do
should :send_email => {
:from => '[email protected]',
:to => '[email protected]',
:subject => 'Your order',
:containing => "important info"
}
end
should "not send email" do
should_not :send_email do
# do something here
end
end
Object creation
should "create something" do
should :create => Something do
# Do something
end
end
should "delete something" do
should :delete => Something do
# Do something
end
end
should "not delete something" do
should_not :delete => Something do
# Do something
end
end
should "not create something" do
should_not :create => Something do
# Do something
end
end
Testing Controllers
Routing
should :route => '/onions/new' do
controller 'onions'
action 'new'
end
-
you need to pass the method if its not a :get request
should :route => '/onions', :method => :post do controller 'onions' action 'create' end
Render
should "show the new order page" do
get :new
should :render => 'orders/new'
end
The default ‘should :render’ checks for a http status code of 200
-
What about other codes?
should "return the not found page when the id does not exist" do get :show, :id => 'something does not exist' should :render_404 => 'public/404' end
Redirection
should "go to the login page if not logged in" do
logout
get :new
should :redirect_to => '/login'
end
Initializing a new object
should "assign a new order" do
get :new
should :assign_new => Order
end
Loading Objects
should "load order by id" do
get :edit, :id => @order.id
assigned(Order).should_be @order
end
-
This checks the object assigned is of the correct type.
Testing the attributes of an assigned object.
should "associate the current user as the editor" do
login_as @user = create_user
put :update, :id => @article.id
assigned(Article).editor.should_be @user
end
should "chain as long as you like" do
assigned(Article).editor.first_name.should_be 'pete'
end
-
If you pass a Symbol its just a value based assertion.
should "load a collection" do get :index assigned(:records).should_be [@record_1, @record_2] end
Flash messages
should "notify the user when order was created" do
post :create, :order => attrib
flashed(:notice).should_be 'Yay, Order created!'
end
Controller Helpers
There are also some helpers for manipulating attributes.
I tend to define an attrib method in my funtional tests to represent valid attributes passed to create or update a resource.
-
eg:
def attrib { :first_name => 'Jim', :last_name => 'Bean' } end
Sometimes you want to tests different values, especially invalid ones, to get away from all the merge noise, I have defined these helpers:
missing_attrib
blank_attrib
replace_attrib
add_attrib
-
Means you can write tests like the following:
should_not :create => Order do post :create, :order => blank_attrib(:cc_no) end should :render => 'orders/new'
All funktional assertions are also available as class methods.
context "When doing it all" do
before { :hit_a_controller }
should :render => 'somethings/new'
should :render_404 => 'public/404'
should :render_404 # (defaults to 'public/404')
should :redirect_to => '/somethings'
element('h1').should_be 'Something' # (you need should_pricot for this one).
count('#friends ol.remaining').should_be 'Not Many' # (should_pricot here too)
flashed(:notice).should_be 'Cool'
should :assign_new => Something
assigned(Something).name.should_be 'something'
assigned(:something).should_be { @something }
should :create => Something
should :delete => Something
should_not :create => Something
should_not :delete => Something
should :send_email => {
:from => '[email protected]',
:to => '[email protected]'
}
should_not :send_email
end
Copyright © 2009 [Brent Greeff], released under the MIT license