📜 ⬆️ ⬇️

Request spec in Action

Testing has become an integral part of any software product development, be it an application for a desktop computer, mobile device or web. Already no one denies the importance of this stage and the consequences that its absence will bring. Among them are a lot of time checking every element (page), and unexpected surprises in the behavior of the product, increasing the cost of fixing the program. The principle of writing tests is quite simple - "yellow color", "red color", "green color", refactoring. Where yellow is not a created test (pending), red is not a passed test, and green is for the system to work as it should.

For each type of programming, there are many types of testing. But there are common points present everywhere. Since the main kind of my work is the creation of web applications under ROR, let's talk about the features of testing application data.


Environment setup

')
You can find many test environments (Test Unit, Rspec, Cucumber & etc), but I personally use Rspec myself. It allows you to give the tests a beautiful view, but at the same time preserve the appearance of the code. Add a new group to the gemfile:

group :development, :test do
gem "rspec-rails", ">= 2.5"
end


You may be surprised and ask: “Why add rspec in development mode?” Everything is quite simple - rspec adds the corresponding specs when generating model, controller, scaffold. Having installed gem, we will carry out the last installation command:

rails g rspec:install

Now we can run our tests with the rake rspec command. The negative side of this approach is that with the slightest change in our project, we will have to perform this command again and again, which will run absolutely all tests. From this it follows that it is necessary to find some watcher so that instead of us he performs the necessary commands. At the moment I know about two quite good solutions - autotest and guard. Autotest came to rails from other frameworks, having proved itself well, and I used only it before. But recently I met a charming solution in the form of guard. By itself, the guard does not carry the necessary functionality, but when used with add-ons, it turns out to be a very smart thing. These additions have about 2 dozen guards, and they carry tremendous opportunities. However, let us dwell on one thing - guard-rspec. Install the necessary files:

group :test do
gem 'guard-rspec'
end


Execute the initialization command:

guard init .
guard init rspec


The first will create a guardfile (observer configuration file), the second will add rspec-specific actions. Now, with the guard command, the watcher works for you, ready to pull the required spec at any time. But the log of this solution is quite boring, so we will add some colors to it. First, install the notification library. And here we are faced with the first problems - you have a different OS with a partner (Mac OS and Linux), and everyone needs to be tested. The solution for us was the following solution:

gem 'libnotify' , :require => false if RUBY_PLATFORM =~ /linux/i
gem 'rb-inotify', :require => false if RUBY_PLATFORM =~ /linux/i
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i


Next, replace all points in rspec with a percentage calculation:

gem 'fuubar'

And finally, in the Guardfile we write the following:

guard 'rspec', :cli =>'--format Fuubar --color'

Run the tests. In the console we get a beautiful progress bar, and at the end of the test - a pop-up window.

The next step to set up a test environment is to make our tests clean. After all, no one wants to, when performing tests, we come across values ​​and records in the database from previous checks. A good choice is gem database_cleaner. Its configuration is shown below:

config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end

config.before(:each) do
DatabaseCleaner.start
end

config.after(:each) do
DatabaseCleaner.clean
end


After setting up the cleaner, it's nice to talk about creating testable content. Rspec suggests using mock-i, but personally I prefer to generate real objects. You can use machinist or factory_girl to create various objects. I don’t know much about machinist, so I can’t say anything about it. But I have been working with factory_girl for a long time, and I never caused any complaints about the gem. Add our gems to the test group:

group :test do
gem 'guard_rspec'
gem 'factory_girl_rails'
gem 'database_cleaner'
end


The rest of the use I propose to consider outside this article by reference.

Self testing


By installing a basic testing environment, you can talk about its features. Rspec divides all testing in parts, that is, copies of folders in the app section are created in the spec folder. During my modest period of development and testing, I found it appropriate only sections models, helpers, mailers. And then the question arises: “What to do with the most important components of controllers and views?” In my opinion, the solution that rspec offers is not entirely complete, and it creates an unrealistic situation of what is happening. Therefore, for my development, I chose to test requests and responses received. To do this, install capybara. The author of the library (Jonas Nicklas) describes it as follows:

“Capybara aims to simplify testing Rack applications such as Rails, Sinatra or Merb. Capybara simulate show web user experience. ”

What literally sounds like:

"Capybara guinea pig simplifies the process of integrated testing, simulating user behavior in your application"

Add it to the gemfile. Then in the spec / test_helper.rb file you need to add the Capybara libraries:

require 'capybara/rspec'

Now our tests are filled with many functional and convenient methods of testing and manipulating the virtual page. Let's start in order:

A visit to the page is done by a clear visit method:

visit '/'

In addition to string addresses, the method accepts rails path helper:

visit car_wheels_path(car)

But the main functionality of the library is in the accessible page object. This object is a virtual page for testing. To get its content, you only need to refer to the body method:

puts page.body

Let's go through the list of commands manipulation. Text and password fields are filled in by the fill_in method, which takes the first parameter id, class, name of the element, and the parameter with specifies the contents:

fill_in 'car_manufacture', :with=>'Audi'
fill_in 'car[model]', :with=>'A4'


To select a variant in select, the select method is used (thanks, Kep), which first takes a value, and then an element for manipulation:

select 'Silver',: from => 'car [color]'

There are also methods check, uncheck, choose, the purpose of which is to change the state of the checkbox and radio button. They only accept the item ID:

check 'car[full_package]'
choose 'car[year][2010]'


But it happens that in the page there are several elements with the same name, or, God forbid, id. For this there is a block method within, which limits the search inside the specified element:

within 'form#payment_card' do
#
end


There are several methods for clicking buttons and links - universal (click_on) and specific (click_link, click_button):

click_on 'submit_form'
click_link 'read_more'


We now turn to verification of the structure obtained. To check for the presence of a DOM element, the have_selector method is present:

page.should have_selector('table tr')

And what if you need to check the number of these elements? Here and there, everything is quite simple - add the count parameter:

page.should have_selector('table tr', :count=>3)

In situations where the element itself is not fazhen, and only the content is important is the page.have_content method useful?

page.should have_content(“Audi club”)

What about js?


Having written a couple of specs, you have already noticed that capybara completely ignores js scripts. The developers have done this step due to the preservation of speed in passing the tests. When there is a need to check our page with full functionality, use the parameter js spec:

it 'should have many js', :js=>true do
visit …
end


A favorite browser window will appear in front of us, a test page will open, and the cursor will do all the movements. Just magic, but let's figure it out. In fact, capybara simply switched the web driver to handle the test page. By default, the rack driver is used, which operates only with the content received with the response. When using the js parameter, capybara starts to handle the selenium driver. Selenium launches the system browser, if not specified, and performs all the desired actions. Everything is good and beautiful, except for a couple of moments. First, the test execution time becomes very long. And not surprisingly, in addition to loading the rails environment itself, the test launches the browser, plus performing the manipulations also takes a certain amount of time. Secondly, I did not like the constant display of the browser. Therefore, I had to abandon selenium in favor of the alternative web driver, capybara-webkit. This gem was specifically written to solve these problems. To install the library, besides capybara-webkit itself, it is necessary to install another qt library. After spec_helper we specify which driver to use for pages with javascript:

Capybara.javascript_driver :webkit

Now capybara will perform integral tests quickly and without any animation.

Another interesting thing you will encounter is the verification of elements that are loaded using ajax. The have_selector and have_content methods do not always pass, so we use methods such as all, find, first:

first('div.info').should be

all('tr.ads').should have(3).items


Also, the find and first methods can be useful for emulating clicks on items other than buttons and links.

first('div.catalog').click
find('p#info).click


If you wanted to execute any script, then capybara will be useful here as well:

page.execute_javascript “alert('Hello world')”

Initially, it seems utter nonsense - “Well, what's the point of performing js tests?” And the answer will be when you need to follow the page’s behavior to actions other than click and select:

page.execute_javascript '$(“p.long_text”).hover();'

This is how we emulated a paragraph cursor.

Couple of life observations

And at the end of my post a couple of tips from personal experience. When using capybara, database_cleaner and factory_girl with any js web driver, the created resources will not be displayed on the test page. To correct this situation the following setting:

config.use_transactional_fixtures = false

Another interesting trick is to focus on rspec, the effectiveness of which is indisputable in resource-intensive tests. Adjusting the focus is as follows. First, add the following line to the test environment configuration file:

config.filter_run :focus=>true
config.run_all_when_everything_filtered = true


After that, to perform actions of interest, it will suffice to add a named parameter: focus => true and the list of specs will be filtered.

useful links


Capybara
Capybara webkit
Data base cleaner
Factory girl rails
Guard

Source: https://habr.com/ru/post/130766/


All Articles