I create a basic Rails 5 application, add an scaffold and create some basic tests on the model. I use RSpec for the test environment, Factory Girl for the factories and Faker to generate some test data. Ready? Let’s go!.
Step 1. Prepare the basic infrastructure
I’am using RVM to keep the Rails’ versions under control, but you can use other tool to do it; the important thing here is to choose Rails 5 in your environment.
So I create the app as usual.
$ rvm list | |
rvm rubies | |
ruby-1.9.3-p484 [ x86_64 ] | |
ruby-2.1.0 [ x86_64 ] | |
ruby-2.2.0 [ x86_64 ] | |
ruby-2.2.2 [ x86_64 ] | |
=* ruby-2.3.0 [ x86_64 ] | |
# => - current | |
# =* - current && default | |
# * - default | |
$ rails new basic_rspec |
Then I can add the corresponding gems to Gemfile:
... | |
group :development, :test do | |
gem 'rspec-rails' | |
gem 'rails-controller-testing' | |
gem 'factory_girl_rails' | |
gem 'faker' | |
# Call 'byebug' anywhere in the code to stop execution and get a debugger console | |
gem 'byebug', platform: :mri | |
end | |
... |
The next step is to install the gems, generate the basic RSpec infrastructure and create the scaffold for our Person class, the class I will use as example:
$ bundle install | |
Resolving dependencies... | |
Using rake 12.0.0 | |
Using concurrent-ruby 1.0.2 | |
Using i18n 0.7.0 | |
... | |
(more gems here...) | |
... | |
Using web-console 3.4.0 | |
Using rails 5.0.0.1 | |
Using sass-rails 5.0.6 | |
Bundle complete! 19 Gemfile dependencies, 72 gems now installed. | |
Use `bundle show [gemname]` to see where a bundled gem is installed. | |
$ rails generate rspec:install | |
Running via Spring preloader in process 4039 | |
Expected string default value for '--jbuilder'; got true (boolean) | |
create .rspec | |
create spec | |
create spec/spec_helper.rb | |
create spec/rails_helper.rb | |
$ rails generate scaffold Person name:string age:integer | |
Running via Spring preloader in process 4046 | |
Expected string default value for '--jbuilder'; got true (boolean) | |
invoke active_record | |
create db/migrate/20161207175605_create_people.rb | |
create app/models/person.rb | |
invoke rspec | |
create spec/models/person_spec.rb | |
invoke factory_girl | |
create spec/factories/people.rb | |
invoke resource_route | |
route resources :people | |
invoke scaffold_controller | |
create app/controllers/people_controller.rb | |
invoke erb | |
create app/views/people | |
create app/views/people/index.html.erb | |
create app/views/people/edit.html.erb | |
create app/views/people/show.html.erb | |
create app/views/people/new.html.erb | |
create app/views/people/_form.html.erb | |
invoke rspec | |
create spec/controllers/people_controller_spec.rb | |
create spec/views/people/edit.html.erb_spec.rb | |
create spec/views/people/index.html.erb_spec.rb | |
create spec/views/people/new.html.erb_spec.rb | |
create spec/views/people/show.html.erb_spec.rb | |
create spec/routing/people_routing_spec.rb | |
invoke rspec | |
create spec/requests/people_spec.rb | |
invoke helper | |
create app/helpers/people_helper.rb | |
invoke rspec | |
create spec/helpers/people_helper_spec.rb | |
invoke jbuilder | |
create app/views/people/index.json.jbuilder | |
create app/views/people/show.json.jbuilder | |
create app/views/people/_person.json.jbuilder | |
invoke assets | |
invoke coffee | |
create app/assets/javascripts/people.coffee | |
invoke scss | |
create app/assets/stylesheets/people.scss | |
invoke scss | |
create app/assets/stylesheets/scaffolds.scss |
I edit the model in order to add two validations and a new method ‘identifier’ that returns a concatenated string. The validations and the method will be used later on the tests.
# app/models/person.rb | |
Person < ApplicationRecord | |
validates :name, presence: true | |
validates :age, presence: true | |
def identifier | |
[name, age].join " " | |
end | |
end |
With this in place I migrate the database and prepare the tests. At this point I should be able to execute the test created by the scaffold (31 in total in this case).
$ rake db:migrate | |
== 20161207175605 CreatePeople: migrating ===================================== | |
-- create_table(:people) | |
-> 0.0010s | |
== 20161207175605 CreatePeople: migrated (0.0010s) ============================ | |
$ rake db:test:prepare | |
$ rspec | |
... | |
Finished in 1.58 seconds (files took 1.64 seconds to load) | |
31 examples, 0 failures, 17 pending |
Step 2. Add the factories
Add the factories to create valid objects to be used in the tests. To do so create the ‘people.rb’ file (note the file name ‘people’, plural of ‘person’). I also include Faker to generate fake values on the object’s attributes.
# spec/factories/people.rb | |
require 'faker' | |
FactoryGirl.define do | |
factory :person do | |
name { Faker::Name.first_name } | |
age { Faker::Number.between(0, 100) } | |
end | |
end |
Step 3. Add the tests
I will verify the Person class has a valid factory, that it is not valid without a name and an age, and that the ‘identifier’ method returns a valid value. This shouldn’t be difficult.
# spec/models/person_spec.rb | |
require 'rails_helper' | |
RSpec.describe Person, type: :model do | |
it "has a valid factory" do | |
#person = FactoryGirl.build(:person) it is also valid | |
expect(FactoryGirl.build(:person)).to be_valid | |
end | |
it "is invalid without a name" do | |
person = FactoryGirl.build(:person, name: nil) | |
expect(person).not_to be_valid | |
end | |
it "is invalid without an age" do | |
person = FactoryGirl.build(:person, age: nil) | |
expect(person).not_to be_valid | |
end | |
it "returns a person's identifier as a string" do | |
person = FactoryGirl.build(:person, name: "Johnny", age: 12) | |
expect(person.identifier).to eq("Johnny 12") | |
end | |
end |
Et voila! I can easily execute the test… with 0 failures!!
$ rspec spec/models/person_spec.rb | |
... | |
Finished in 0.39298 seconds (files took 2.32 seconds to load) | |
4 examples, 0 failures |
Is this post useful for you? Would you improve/change something? Please add a comment and explain your idea to all of us. Thanks!