Request spec in Action
Testing has become an integral part of any software product development, whether it is 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, a lot of time to check each element (page), and unexpected surprises in the behavior of the product, an increase in the cost of fixing the program. The principle of writing tests is quite simple - “yellow”, “red”, “green”, refactoring. Where yellow is the pending test, red is the failed test, and green is the system working as it should.
For each type of programming, there are many types of testing. But there are common points that are present everywhere. Since the main kind of my work is creating web applications under ROR, let's talk about the features of testing these applications.
You can find many test environments (Test Unit, Rspec, Cucumber & etc), but I personally actively use Rspec. It allows you to give the tests a beautiful look, but at the same time maintain the look of the code. We’ll add a new group to the gemfile: you may be surprised and ask: “Why add rspec to development mode?” Everything is quite simple - rspec adds the appropriate specs when generating model, controller, scaffold. After installing gem, let's run the last installation command:
Now we can run our tests with the rake rspec command. The negative side of this approach is that at the slightest change in our project, we will again and again have to execute this command, which will pull through absolutely all the tests. It follows that it is necessary to find some watcher so that it executes the necessary commands instead of us. At the moment I know about two good solutions - autotest and guard. Autotest came to rails from other frameworks, having proved itself well, and earlier I used only it. But recently, I met with a lovely solution in the form of a guard. The guard itself does not carry the necessary functionality, but when you use it with add-ons, it turns out a very gorgeous thing. The guard has about 2 dozen of these additions, and they carry enormous opportunities. However, let us dwell on one thing - guard-rspec. Install the necessary files:
We execute the initialization command: The first will create a guardfile (observer configuration file), the second will add rspec-specific actions. Now, on the guard command, you have watcher working, ready at any time to draw up the necessary spec. But the log for this solution is quite boring, so add a little color to it. First, install the notification libraries. And here we are faced with the first problems - you and your partner have different OS (Mac OS and Linux), but everyone needs to test. The solution for us was the following solution: Next, we replace all the points in rspec with a percentage calculus: And finally, in the Guardfile we write the following: Run the tests. In the console, we get a beautiful progress bar, and when the test finishes, a pop-up window appears.
The next step for setting up a testing environment is to make our tests clean. After all, no one wants us to come across values and records in the database from previous checks when performing tests. A good choice in this case might be gem database_cleaner. Its configuration is shown below: After setting up the cleaner, it's nice to talk about creating testable content. Rspec suggests using mock, but personally, I prefer to generate real objects. You can use machinist or factory_girl to create various objects. I am not particularly familiar with machinist, so I can’t say anything about him. But I’ve been working with factory_girl for a long time, and gem has never raised any complaints. Add our gems to the test group:
The rest of the use I suggest to consider outside this article at the link
Having established a basic testing environment, you can talk about its features. Rspec divides all testing in parts, that is, copies of the folders in the app section are created in the spec folder. During my modest period of development and testing, I only found the models, helpers, mailers sections useful. 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 a not very real situation. Therefore, for my development, I chose to test requests and received responses. To do this, install capybara. The author of the library (Jonas Nicklas) describes it like this:
“Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb. Capybara simulate show a real user would interact with a web application. ”
Which literally sounds like:
“ Capybaraguinea pig simplifies the process of complex testing, simulating user behavior in your application”
Add it to the gemfile. After you need to add Capybara libraries in the file spec / test_helper.rb:
Now our tests are filled with many functional and convenient testing methods and manipulating a virtual page. Let's start in order:
A visit to the page is done in the clear visit method:
In addition to lowercase addresses, the method accepts rails path helper:
But the main functionality of the library is the accessible page object. This object is a virtual page for testing. To get its contents, you just need to turn to the body method:
Let's go through the list of manipulation commands. Text and password fields are filled with the fill_in method, which takes the first parameter as the id, class, name of the element, and the with parameter sets the content: To select an option, select uses the select method (thanks, Kep), which first takes a value and then the element for manipulation : select 'Silver',: from => 'car [color]' There are also check, uncheck, choose methods whose purpose is to change the state of the checkbox and radio button. They accept only the identifier of the element:
But it happens that in the page there are several elements with the same name, or, God forbid, id. To do this, there is a within block method that restricts the search inside the specified element: To click buttons and links, there are several methods - universal (click_on) and specific (click_link, click_button): Now let's move on to checking the resulting structure. To check for the presence of a DOM element, the have_selector method is present: But what if you need to check the number of these elements? That's all simple enough - we add the count parameter: In situations where the element itself is not fazhn, and it is important only the page.have_content method is useful?
Having written a couple of specs, you already noticed that capybara completely ignores js scripts. The developers took this step due to the preservation of performance when passing the tests. When there is a need to check our page with full functionality, we use the js spec parameter:
A window of your favorite browser will appear before us, the tested page will open, and the cursor will do all the movements. Just magic, but let's figure it out. Actually capybara just switched the web driver to process the test page. By default, the rack driver is used, which operates only on the content received with the response. When using the js parameter, capybara begins to handle the selenium driver. Selenium launches a system browser, unless otherwise specified, and performs all desired actions. Everything is good and beautiful, except for a couple of points. Firstly, the test run time becomes very long. And not surprisingly, in addition to loading the rails environment itself, the test launches the browser, plus the manipulations also take some time. Secondly, I was not happy with the constant display of the browser. Therefore, I had to abandon selenium in favor of an alternative web driver - capybara-webkit. This gem was specially written to solve these problems. To install the library, in addition to capybara-webkit itself, you need to install another qt library. After spec_helper we specify which driver to use for pages with javascript:
Now capybara will perform integrated tests quickly and without unnecessary animation.
Another interesting point that you come across will be checking the elements that are loaded using ajax. The have_selector and have_content methods do not always work, so we use methods such as all, find, first: Also, the find and first methods can be useful for emulating clicks on elements other than buttons and links. If you wanted to execute some kind of script, then capybara will come in handy here: Initially, this seems like complete nonsense - "Well, what's the point of running js tests?" And the answer will be a situation where you need to trace the behavior of the page to actions other than click and select: This is how we emulated the hover over a paragraph of the cursor.
A couple of observations from life
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:
Another interesting trick is the focus in rspec, the effectiveness of which is undeniable in resource-intensive tests. Focus adjustment is as follows. First, add the lines to the configuration file of the testing environment: After, to perform the actions of interest, it will be enough to add a parameter named: focus => true and the list of specs will be filtered.
Capybara
Capybara Webkit
Data base cleaner
Factory girl rails
Guard
For each type of programming, there are many types of testing. But there are common points that are present everywhere. Since the main kind of my work is creating web applications under ROR, let's talk about the features of testing these applications.
Environment setup
You can find many test environments (Test Unit, Rspec, Cucumber & etc), but I personally actively use Rspec. It allows you to give the tests a beautiful look, but at the same time maintain the look of the code. We’ll add a new group to the gemfile: you may be surprised and ask: “Why add rspec to development mode?” Everything is quite simple - rspec adds the appropriate specs when generating model, controller, scaffold. After installing gem, let's run the last installation command:
group :development, :test do
gem "rspec-rails", ">= 2.5"
end
rails g rspec:install
Now we can run our tests with the rake rspec command. The negative side of this approach is that at the slightest change in our project, we will again and again have to execute this command, which will pull through absolutely all the tests. It follows that it is necessary to find some watcher so that it executes the necessary commands instead of us. At the moment I know about two good solutions - autotest and guard. Autotest came to rails from other frameworks, having proved itself well, and earlier I used only it. But recently, I met with a lovely solution in the form of a guard. The guard itself does not carry the necessary functionality, but when you use it with add-ons, it turns out a very gorgeous thing. The guard has about 2 dozen of these additions, and they carry enormous opportunities. However, let us dwell on one thing - guard-rspec. Install the necessary files:
group :test do
gem ‘guard-rspec’
end
We execute the initialization command: The first will create a guardfile (observer configuration file), the second will add rspec-specific actions. Now, on the guard command, you have watcher working, ready at any time to draw up the necessary spec. But the log for this solution is quite boring, so add a little color to it. First, install the notification libraries. And here we are faced with the first problems - you and your partner have different OS (Mac OS and Linux), but everyone needs to test. The solution for us was the following solution: Next, we replace all the points in rspec with a percentage calculus: And finally, in the Guardfile we write the following: Run the tests. In the console, we get a beautiful progress bar, and when the test finishes, a pop-up window appears.
guard init .
guard init rspec
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
gem 'fuubar'
guard 'rspec', :cli =>'--format Fuubar --color'
The next step for setting up a testing environment is to make our tests clean. After all, no one wants us to come across values and records in the database from previous checks when performing tests. A good choice in this case might be gem database_cleaner. Its configuration is shown below: After setting up the cleaner, it's nice to talk about creating testable content. Rspec suggests using mock, but personally, I prefer to generate real objects. You can use machinist or factory_girl to create various objects. I am not particularly familiar with machinist, so I can’t say anything about him. But I’ve been working with factory_girl for a long time, and gem has never raised any complaints. Add our gems to the test group:
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
group :test do
gem ‘guard_rspec’
gem ‘factory_girl_rails’
gem ‘database_cleaner’
end
The rest of the use I suggest to consider outside this article at the link
Testing itself
Having established a basic testing environment, you can talk about its features. Rspec divides all testing in parts, that is, copies of the folders in the app section are created in the spec folder. During my modest period of development and testing, I only found the models, helpers, mailers sections useful. 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 a not very real situation. Therefore, for my development, I chose to test requests and received responses. To do this, install capybara. The author of the library (Jonas Nicklas) describes it like this:
“Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb. Capybara simulate show a real user would interact with a web application. ”
Which literally sounds like:
“ Capybara
Add it to the gemfile. After you need to add Capybara libraries in the file spec / test_helper.rb:
require 'capybara/rspec'
Now our tests are filled with many functional and convenient testing methods and manipulating a virtual page. Let's start in order:
A visit to the page is done in the clear visit method:
visit ‘/’
In addition to lowercase addresses, the method accepts rails path helper:
visit car_wheels_path(car)
But the main functionality of the library is the accessible page object. This object is a virtual page for testing. To get its contents, you just need to turn to the body method:
puts page.body
Let's go through the list of manipulation commands. Text and password fields are filled with the fill_in method, which takes the first parameter as the id, class, name of the element, and the with parameter sets the content: To select an option, select uses the select method (thanks, Kep), which first takes a value and then the element for manipulation : select 'Silver',: from => 'car [color]' There are also check, uncheck, choose methods whose purpose is to change the state of the checkbox and radio button. They accept only the identifier of the element:
fill_in ‘car_manufacture’, :with=>’Audi’
fill_in ‘car[model]’, :with=>’A4’
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. To do this, there is a within block method that restricts the search inside the specified element: To click buttons and links, there are several methods - universal (click_on) and specific (click_link, click_button): Now let's move on to checking the resulting structure. To check for the presence of a DOM element, the have_selector method is present: But what if you need to check the number of these elements? That's all simple enough - we add the count parameter: In situations where the element itself is not fazhn, and it is important only the page.have_content method is useful?
within ‘form#payment_card’ do
#много манипуляций
end
click_on ‘submit_form’
click_link ‘read_more’
page.should have_selector('table tr')
page.should have_selector(‘table tr’, :count=>3)
page.should have_content(“Audi club”)
But what about js?
Having written a couple of specs, you already noticed that capybara completely ignores js scripts. The developers took this step due to the preservation of performance when passing the tests. When there is a need to check our page with full functionality, we use the js spec parameter:
it ‘should have many js’, :js=>true do
visit …
end
A window of your favorite browser will appear before us, the tested page will open, and the cursor will do all the movements. Just magic, but let's figure it out. Actually capybara just switched the web driver to process the test page. By default, the rack driver is used, which operates only on the content received with the response. When using the js parameter, capybara begins to handle the selenium driver. Selenium launches a system browser, unless otherwise specified, and performs all desired actions. Everything is good and beautiful, except for a couple of points. Firstly, the test run time becomes very long. And not surprisingly, in addition to loading the rails environment itself, the test launches the browser, plus the manipulations also take some time. Secondly, I was not happy with the constant display of the browser. Therefore, I had to abandon selenium in favor of an alternative web driver - capybara-webkit. This gem was specially written to solve these problems. To install the library, in addition to capybara-webkit itself, you need 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 integrated tests quickly and without unnecessary animation.
Another interesting point that you come across will be checking the elements that are loaded using ajax. The have_selector and have_content methods do not always work, so we use methods such as all, find, first: Also, the find and first methods can be useful for emulating clicks on elements other than buttons and links. If you wanted to execute some kind of script, then capybara will come in handy here: Initially, this seems like complete nonsense - "Well, what's the point of running js tests?" And the answer will be a situation where you need to trace the behavior of the page to actions other than click and select: This is how we emulated the hover over a paragraph of the cursor.
first(‘div.info’).should be
all(‘tr.ads’).should have(3).items
first(‘div.catalog’).click
find(‘p#info).click
page.execute_javascript “alert(‘Hello world’)”
page.execute_javascript ‘$(“p.long_text”).hover();’
A couple of observations from life
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 the focus in rspec, the effectiveness of which is undeniable in resource-intensive tests. Focus adjustment is as follows. First, add the lines to the configuration file of the testing environment: After, to perform the actions of interest, it will be enough to add a parameter named: focus => true and the list of specs will be filtered.
config.filter_run :focus=>true
config.run_all_when_everything_filtered = true
useful links
Capybara
Capybara Webkit
Data base cleaner
Factory girl rails
Guard