A Brief Introduction to Basics of RSpec in Ruby On Rails

April 29, 2015 admin No Comments

A Brief Introduction to Basics of RSpec in Ruby On Rails

A Brief Introduction to Basics of RSpec in Ruby On Rails

RSpec is a library that focuses on testing the behavior of your everyday projects for Ruby programming language. Developers are usually reluctant to use it because probably testing practice is the most difficult mindset a developer has to learn.

But once Rspec testing habit is developed and Test Driven Development is in , it becomes really useful in diagnosing problems in large scale applications once they are modified for some changes in future.

In the long term, a developer will not have to check each web page every time a new feature is added, but he will only check if the specific test passed and so handling of large applications becomes a convenient task.

Born under the banner of Behavior-Driven Development, Rspec is a productive and enjoyable automated testing experience with features like:

-a rich command line program (the rspec command)

-textual descriptions of examples and groups (rspec-core)

-flexible and customizable reporting

-extensible expectation language (rspec-expectations)

-built-in mocking/stubbing framework (rspec-mocks)

The post is a brief step by step process to setup RSpec with your project and use it. The tests for rspec will be written in capybara language, which is similar to natural language and is widely used for testing purposes. Capybara helps you test web applications by simulating how a real user would interact with your app.

It is agnostic about the driver running your tests and comes with Rack::Test and Selenium support built in. WebKit is supported through an external gem. (https://rubydoc.info/gems/capybara/2.2.1/frames)

1. Include gem ‘rspec-rails’, gem “capybara”, “~> 2.1.0”, gem “shoulda”, “~> 3.3.2”, gem ‘factory_girl_rails’

In your command line install the rspec gems:

2. gem install rspec

3. gem install rspec-rails

4. gem install capybara

Generate the rspec testing module files using this command

5. script/rails generate rspec:install

Run bundle installer

6. bundle install

Run required migrations

7. rake db:migrate RAILS_ENV=development

8. Include require ‘rspec/rails’, require ‘capybara/rspec’ in you spec_helper file

9. Add config.include Capybara::DSL in the same file to make Capybara available in all test cases deriving from ActionDispatch::IntegrationTest:

Generators

Once the environment is set. Its time to generate the testing files. There are different test types including, model , view, controller,and integeration tests. Other types of tests are request, mailer and helper tests.

They are written as per requirements to cover every aspect of the application. This article will cover commands and examples related to the most commonly used type of Rspec Tests.

-rails generate rspec:model model_name

-rails generate rspec:controller contoller_name

-rails generate rspec:view folder_name view_name

-rails generate integration_test feature_name

Execution Commands

To run specific tests from command line following commands should be used:

Models: bundle exec rspec spec/models/search_phrase_spec.rb

Controllers: bundle exec rspec spec/controllers/users_controller_spec.rb

Views: bundle exec rspec spec/views/search_phrases/index.html.erb_spec.rb

Integration: bundle exec rspec spec/features/search_phrases_spec.rb

The Naming convention for the Rspec Testing files:

Models: modelname_spec.rb

Controllers: controllername_controller_spec.rb

Views: viewname.html.extensionname_spec.rb

Integeration: featurename_spec.rb

Example of Tests

Stub method to simulate dummy user creation and devise sign_in authentication before tests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
before:all do
@user = User.find_by_name('testuser')
@user ||=begin
user = User.new(email:"test@gmail.com",
password:"$2a$10$T",
uid:"10000697585", name:"testuser",
authority_token:"AUExuiUkFoBAEsYd")
user.save!
user
end
end
 
before:each do
User.stub(:current_user).and_return(@user)
sign_in@user
end

OR USE FactoryGirl to create the user for model test

1
2
3
4
5
6
7
8
9
10
11
FactoryGirl.definedo
factory:user do |user|
 
user.email"testformodel@gmail.com"
user.password"$2a$10$T"
user.uid"10000697585"
user.name"testuserformodel"
user.authority_token"AUExuiUkFoBAEsYd"
end
 
end

You can use either of the above mentioned codes as per need.

Models

Here is an example code for the associated models:

class SearchPhrase

2. # bowling.rb

1
2
3
4
5
6
7
8
class Bowling
def hit(pins)
end
 
def score
0
end
end

Following are the related Rspec tests:

Test

First of all:

1. # search_phrase_spec.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
require'spec_helper'
class ValidatingWidget
2.# bowling_spec.rb
<preclass="brush: ruby">require'bowling'
describe Bowling,"#score" do
it"returns 0 for all gutter game" do
bowling = Bowling.new
20.times { bowling.hit(0) }
bowling.score.should eq(0)
end
end
</pre><p>
These tests will passwhen executed</p>
<h3>Controller</h3>
<p>In this example a controller method creates search phrasesfor a specific user using keywordsand saves themin database<br>
#search_phrase_controller.rb</p>
<preclass="brush: ruby">def create
@search_phrase = current_user.search_phrases.new(params[:search_phrase].permit(:keyword))
if @search_phrase.save
redirect_to search_phrases_path, notice:'Search Phrase was successfully created.' }
end
end
</pre><p>
Following are the related Rspec tests:</p>
<h3>Test</h3>
<p>#search_phrase_controller_spec.rb</p>
<preclass="brush: ruby">require'spec_helper'
describe SearchPhrasesControllerdo
include Devise::TestHelpers
describe"POST #create" do
it"should pass params to search phrases" do
post:create ,search_phrase: {keyword:'testkeywordnew'}
assigns[:search_phrase].keyword.should =='testkeywordnew'
end
it" should redirect to 'index' with a notice on successful save" do
post:create ,search_phrase: {keyword:'testkeywordnew'}
response.should redirect_to(search_phrases_path)
end
end
</pre>
<h3>View</h3>
<p>This example is shows the index page of the search phrase example appfor which the tests are written<br><br>
#index.html.erb</p>
<preclass="brush: ruby"><div> </div>
<h2> </h2>
<div> <button>Add Keyword</button></div>
<br><div>
 
 'new' %>
</div>
 
<div>
 
<table><thead><tr><td>Keywords</td>
<td>Options</td>
</tr></thead><tbody><tr id="table-row-<%=keyword.id%>"><td>
<div></div>
<div>
 'edit',:locals => {:search_phrase => keyword} %>
</div>
</td>
<td>
<button id="button-edit-<%=keyword.id%>" class="btn btn-info"><iclass="icon-pencil icon-white"></i></button>
 
</td>
</tr></tbody></table></div>
</pre>
<h3>Test</h3>
<p>Following are the related Rspec tests:</p>
<p>#index.html.erb_spec.erb</p>
<preclass="brush: ruby">require'spec_helper'
 
describe"search_phrases/index.html.erb" do
include Devise::TestHelpers
 
<put user="" sign="" in="" stub="" here="" if="" devise="" authentication="" required="">
 
#Mock model is creating a virtual model to write view tests
let(:search_phrase)do
mock_model('SearchPhrase',
:id =>1,
:keyword =>'testkeyword2',
:user_id =>@user.id,
:created_at =>Time.utc(2000))
end
 
beforedo
assign:search_phrases, []
end
 
#displays and renders the pages
it"renders the template 'index.html.erb_spec'" do
 
puts"*--Search Phrases #{@search_phrases.to_yaml}"
render
expect(view).to render_template("search_phrases/index","search_phrases/_new")
end
 
#displays script
it "displays the script tag '<script>
<!--//--><![CDATA[// ><!--
<!--//--><![CDATA[// ><!--
'"do
render
expect(rendered).to match /<script>/
end
 
it"displays the user image in index" do
render
expect(rendered).to include(@user.image)
end
 
it"displays the user name in index" do
render
expect(rendered).to include(@user.name)
end
 
it"displays the button Text 'Add Keyword'" do
render
expect(rendered).to match /Add Keyword/
end
 
it"displays the button 'Add Keyword'" do
render
puts"*Rendered View #{rendered}"
rendered.should have_button('Add Keyword')
end
 
it"displays the heading'Keyword'" do
render
rendered.should have_content('Keyword')
end
 
it"displays the button 'Add Keyword'" do
render
rendered.should have_button('Add')
end
 
end
 
//--><!]]]]><![CDATA[>
//--><!]]>
</script></put></pre><h3>Integration</h3>
<p>Integration tests deal with the integration functions of a complete set of application function. For the scope of this post, we are taking example of a page, where user opens a web page, the application checksif user is signedin or not,if user is signedin, the user has authority to perform search function using a keyword phrase,and editor update the search phrases.</p>
<h3>Test</h3>
<p>The tests show how these functions are tested:</p>
<preclass="brush: ruby">describe"SearchPhrases" do
 
#@user stub code for authentication or phrase creation>
 
#===========TESTS START=========================================================
# '/' refers to home of application
 
def logged_in?
page.has_selector?"username", text:"Sign Out"
end
 
describe"Go to Application Start" do
 
it"should not have user logged in before" do
visit'/'
logged_in?.should ==false
end
 
it"should have the content 'Welcome to Demo Application'" do
visit'/'
expect(page).to have_content('Welcome to Demo Application')
end
end
 
describe"check images and icons" do
 
it"should have the Demo logo" do
visit'/'
puts"*Demo Logo xpath-> #{:xpath.to_s}"
page.should have_css("img[src*='arkhitech']")
end
end
 
describe"After User Logs In", js:true do
 
before:each do
 
unless logged_in?
visit'/'
OmniAuth.config.mock_auth[:provider] = {
provider:'provider',
uid:@user.uid,
credentials: {
token:@user.provider_token
}
}
click_link"Sign in"
end
end
 
it"should be logged in" do
logged_in?.should ==true
end
 
it"should show the name of user" do
page.should have_content"#{@user.name}"
end
 
it"should show the display picture of user" do
page.should have_css("img[src*='#{@user.image}']")
end
 
#------------------------------- Now Add Key Word Button Pressed----------------
 
it"click button 'Add Keyword' and display Keyword heading" do
find('#toggleKeywordAdd').click
expect(page).to have_content('Keyword')
 
end
 
it"click button 'Add Keyword' and display edit and remove buttons" do
find('#toggleKeywordAdd').click
fill_in('search_phrase[keyword]',:with =>'KEYWORD_3')
click_button("Add")
expect(page).to have_content('KEYWORD_3')
page.should have_css("button[class*='btn btn-info']")
page.should have_css("a[class*='btn btn-danger remove_fields']")
end
 
it"click button 'Add Keyword', adds keyword and click update button to update" do
find(:css,"button[id*='button-edit-#{@search_phrase.id}']" ).click
page.should have_css("input[class*='btn btn-medium btn-primary']")
page.should have_css("input[id*='search_phrase_keyword']")
fill_in('search_phrase[keyword]',:with =>'KEYWORD_EDIT')
click_button("Update")
expect(page).to have_content('KEYWORD_EDIT')
end
 
it"log out user on Sign Out" do
click_link("Sign Out")
current_path.should eq root_path
logged_in?.should ==false
end
end
end
</pre><p>
These are some comprehensive examples whichI practiced as a beginner. Again practicing brings perfection, so keep practicing with RSpecand getin control of your huge big applications. For your ease, here is quick summary of capybara language commands to write your tests. [courtesy: github/zhengjia]</p>
<p><em>=Navigating=</em><br><em> visit('/projects')</em><br><em> visit(post_comments_path(post))</em></p>
<p><em>=Clicking linksand buttons=</em><br><em> click_link('id-of-link')</em><br><em> click_link('Link Text')</em><br><em> click_button('Save')</em><br><em> click('Link Text')# Click either a link or a button</em><br><em> click('Button Value')</em></p>
<p><em>=Interacting with forms=</em><br><em> fill_in('First Name',:with =>'John')</em><br><em> fill_in('Password',:with =>'Seekrit')</em><br><em> fill_in('Description',:with =>'Really Long Text…')</em><br><em> choose('A Radio Button')</em><br><em> check('A Checkbox')</em><br><em> uncheck('A Checkbox')</em><br><em> attach_file('Image','/path/to/image.jpg')</em><br><em> select('Option',:from =>'Select Box')</em></p>
<p><em>=scoping=</em><br><em> within("//li[@id='employee']")do</em><br><em> fill_in'Name',:with =>'Jimmy'</em><br><em>end</em><br><em> within(:css,"li#employee")do</em><br><em> fill_in'Name',:with =>'Jimmy'</em><br><em>end</em><br><em> within_fieldset('Employee')do</em><br><em> fill_in'Name',:with =>'Jimmy'</em><br><em>end</em><br><em> within_table('Employee')do</em><br><em> fill_in'Name',:with =>'Jimmy'</em><br><em>end</em></p>
<p><em>=Querying=</em><br><em> page.has_xpath?('//table/tr')</em><br><em> page.has_css?('table tr.foo')</em><br><em> page.has_content?('foo')</em><br><em> page.should have_xpath('//table/tr')</em><br><em> page.should have_css('table tr.foo')</em><br><em> page.should have_content('foo')</em><br><em> page.should have_no_content('foo')</em><br><em> find_field('First Name').value</em><br><em> find_link('Hello').visible?</em><br><em> find_button('Send').click</em><br><em> find('//table/tr').click</em><br><em> locate("//*[@id='overlay'").find("//h1").click</em><br><em> all('a').each { |a| a[:href] }</em></p>
<p><em>=Scripting=</em><br><em> result = page.evaluate_script('4 + 4');</em></p>
<p><em>=Debugging=</em><br><em> save_and_open_page</em></p>
<p><em>=Asynchronous JavaScript=</em><br><em> click_link('foo')</em><br><em> click_link('bar')</em><br><em> page.should have_content('baz')</em><br><em> page.should_not have_xpath('//a')</em><br><em> page.should have_no_xpath('//a')</em></p>
<p><em>=XPathand CSS=</em><br><em> within(:css,'ul li') { ... }</em><br><em> find(:css,'ul li').text</em><br><em> locate(:css,'input#name').value</em><br><em> Capybara.default_selector =:css</em><br><em> within('ul li') { ... }</em><br><em> find('ul li').text</em><br><em> locate('input#name').value</em></p>
<h3></h3>
<h3>Further Reading</h3>
<p>Furthur informationand best practices can be reviewd on RDocs:</p>

Leave a Reply