📜 ⬆️ ⬇️

Rails: Enough otmazyvatsya, we start BDD-it!

Who is there?


When it comes to testing an existing product, and even more about developing something new based on the initial writing of usage scenarios, various specifications and tests, you can often hear such things:

 11:24:21 PM Michael: well, i need to try
 11:24:24 PM Michael: that's probably better
 11:24:27 PM Michael: even I think for sure
 11:24:36 PM Michael: but for now, something stops me
 11:24:38 PM Michael: probably laziness :)

Familiar? “ Do not want to understand? No time? "Then read on. The article will tell you how to set up your favorite rail environment to develop with the approach of BDD and start a new life (optional).

Initial data


For the purity of the experiment, let's start from scratch. I hope everyone has been friends with RVM for a long time (if not, run to get to know each other). Great for managing Ruby versions and all related jams. It is put for one team in the terminal window (well, or whatever is not in the macos, the console, probably). Immediately we forget about the privileges of Ruta.
So, create a clean environment:

$ rvm gemset create bdd $ rvm gemset use bdd 

All, no jams, clean space. We put the last rails:
')
 $ gem install rails --no-ri --no-rdoc ... 23 gems installed 

The last two keys are needed to not spend too much time and not to put any unnecessary documentation. I added these keys all the time, so in the end I sent this case to .gemrc :

 $ echo 'gem: --no-ri --no-rdoc' >> ~/.gemrc 

Great, there are rails. At the time of writing, we are using version 3.0.3 .

We collect all the jams


Create a clean application:

 $ rails new bdd 

Immediately open the Gemfile , the one that is at the root. If it does not open, then apparently the wrong text editor, delete Textmate - set MacVim (everyone closed the topic, then I’m not talking ). Add to the file everything you need for testing. In our case, we will use Cucumber and RSpec , as well as a lot of all sorts of goodies, which I will discuss later.

 source 'http://rubygems.org' gem 'rails', '3.0.3' gem 'mysql2' group :development, :test do gem 'rspec-rails' gem 'cucumber-rails' end group :test do gem 'capybara' gem 'database_cleaner' gem 'factory_girl_rails' gem 'email_spec' gem 'timecop' gem 'launchy' end 

The file was corrected, now we put everything:

 $ bundle install ... Your bundle is complete!.. 

Immediately it would be nice to fix all installed versions in the Gemfile , i.e. explicitly prescribe the version as well as the jam rails (the one that is the very first), but in principle it is not critical to test, besides there is a Gemfile.lock .
We are friends with the rails RSpec :

 $ rails g rspec:install 

We're friends with Cucumber and the last with RSpec . Do not forget about Capybara (yes, and it happens, about it just below):

 $ rails g cucumber:install --rspec --capybara 

We will bring beauty

 $ echo '--colour --format documentation' > .rspec 

After that, RSpec will display information on passing tests in a beautiful format. The same can be done for Cucumber . Open config / cucumber.yml and execute :% s / progress / pretty / g (replace progress with pretty ).
Finally, ignore the test folder (just in case, what if) and other trash:

 $ echo 'test' >> .gitignore $ echo '*.swp' >> .gitignore $ echo '.DS_Store' >> .gitignore 

We’ll put everything we’ve done in git (everyone should know Uncle Linus here too):

 $ git init . $ git add . $ git commit -m 'Bare Rails 3.0.3 application with BDD environment' 

So, here is already a cappuccino with cinnamon aside, proceed directly to the development based on the approach of BDD . Here, too, I hope for a general idea of ​​this evil monster (calm, good it). Google to the rescue.

Who is who?


Cucumber

https://github.com/aslakhellesoy/cucumber
So, Cucumber , a cucumber, is a tool for “ elegant and joyful BDD ”, which can be found on its main page. Yes, joy will be more than enough, especially at first with the habit. About RSpec , I think the authors could say something like that. In any case, there are a lot of documentation and examples for these friends, which only some wiki pages on the githaba are worth , so I will not particularly extend it, just a short one. At once I will make a reservation that everything is in the context of the rails, although, of course, neither RSpec nor Cucumber are limited to this.
Let's return to Cucumber . It allows you to describe the behavior of the system from the perspective of an external observer (read as " customer, end user "). In this case, the description is given in a natural language, no begin end to you. Each option of using the system in a cucumber is called a “ feature ”. All of them are in the features daddy of the same name with an unpredictable * .feature file extension . Each file describes one or several “ scenarios ” ( scenario ) characterizing the feature. Scripts consist of a series of steps announced in the files from the features / step_definitions / * _ steps.rb folder . There are three types of steps: Given (something given, some prerequisite), When (something that happens, some actions of the user) and Then (result, reaction, response), but about such things it is better to live by examples speak. One of my last features (in NG on TV I heard, “ I am not a wizard, I’m just uchus ... ”, in general, it’s very suitable here, don’t judge strictly):

 @javascript @redis
 Feature: A user sees who is online
   In order to know what the portal is alive
   As a regular user
   I want to see who is online

   Background:
     Given the section "Personal profiles" exists

   Scenario Outline: who is online?
     For nobody lot
     And a user exists with name: "<name>"
     When the user "<name>" <user action> the portal
     And I go to the profile of the user "<name>"
     Then I should for my user "<name>"
     When I go to the section "Personal profiles"
     Then I should for my user "<name>"

     Examples:
       |  name |  user action |  my action |
       |  Victoria |  visits |  see |
       |  Michael |  does not visit |  not see |

The keyword " Feature " precedes the name of the feature, according to the rules it should briefly and clearly describe the user's actions. Three lines below it say why, who and what they want. The " Background " section optionally sets general steps for all feature scripts. Next come either " Scenario " or " Scenario Outline ". The first describes the scenario without parameters, the second with the parameters following the keyword " Examples " below. Labels are placed through the dog ( @ ), allowing to impose additional conditions on the entire feature or a specific script, as well as to perform a test selectively. In principle, everything is readable. Ideally, it should be so that the customer takes this file, opens it with a simple text editor and reads without straining, understands everything, realizes and confirms: “ It! "
As for the configuration of the cucumber, it is carried out in the generated file features / support / env.rb. There are added the necessary lines of code to connect all that is needed for testing.

RSpec

https://github.com/rspec/rspec
RSpec is also used to describe the external behavior of the system, but is more suitable for digging into its insides. That is, if you need to check that some model behaves adequately or that some kind of samopisnaya library justifies the hopes placed on it, then RSpec itself . But if you want to check that “the user, having entered his e-mail in the first window, and the second, the password, saw a message about successful login, ” then this is to Cucumber . Each RSpec file in common is called “ specs ” ( spec , from specification ), located in the spec folder and ends in * _spec.rb . Files in the spec folder are divided into subfolders so that they reflect the rail project structure ( models , controllers , helpers , etc.). Here is a slightly simulated example:

 describe User do it { should ensure_length_of(:email).is_at_least(6).is_at_most(100) } it { should validate_format_of(:email).with('ma1f0rmed emai1 address') } subject { Factory :user } it { should validate_uniqueness_of :email } it { should validate_uniqueness_of :address } end 

Here, I feel, it shouldn’t have happened, but it’s not about that, but that the specs look like this.
The RSpec configuration is concentrated in the file spec / spec_helper.rb . Similarly, Cucumber's env.rb here comes with all the auxiliary require and stuff.

Capybara

https://github.com/jnicklas/capybara
Capybara is a handy thing for automating “ browser-based ” application testing. Judging by the illustrations from Google, this is some kind of guinea pig, but it's not about her. Jam gives a lot of auxiliary methods in the test environment, with the result that you can easily check such things as, for example, clicking on links, filling out forms (input fields, drop-down lists, checkboxes, etc.), the presence of any element on the page. Moreover, when another piece is connected to it with the equally mysterious name Selenium , it allows you to go through the steps of the test script directly in the browser, in the literal sense. You will see, for example, your favorite Chrome and the pages will run one after another. As a result, you can debug and javascript . It was interesting to observe for the first time how it checked the list sorting on the page by dragging its elements by itself. Selenium is not the only engine with which Capybara can work, but is, in my opinion, the most convenient, and does not require the installation of anything extra, such as JRuby . Selenium is easy enough to ask to check something not only in Chrome , but also in Firefox (the default option) and even in a donkey. In the case of Cucumber, it is enough to open the env.rb file and add the following code indicating the desired browser (see the list of available documents in the Selenium documentation):

 Capybara.register_driver :selenium do |app| Capybara::Driver::Selenium.new app, :browser => :chrome end 


Database cleaner

https://github.com/bmabey/database_cleaner
Jam for database cleaning before or after tests. Convenient to cover the tracks and start from scratch. It supports different databases and adapters to them. I use it both for cleaning MySQL + ActiveRecord , and mongoDB + Mongoid .
If this jam is connected in a gemfile , then when generating the environment, Cucumber will add it to your env.rb automatically, something like:

 require 'database_cleaner' DatabaseCleaner.strategy = :truncation Before do DatabaseCleaner.clean end 

For RSpec, you can write the following in spec_helper.rb (understand where):

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


Factory girl rails

https://github.com/thoughtbot/factory_girl_rails
Oh, and before the girls came! So, this library is used to easily create copies of models (replacement of fixtures that are native to rails, if someone says something about something). In other words, you need to test something with an example. We need both User ( User ), and Article ( Article ), and projects ( Project ) with tasks ( Task ). Do not create objects every time with filling in all required fields. It is here that similar factories come to the rescue. It is enough to define a pattern once and then generate new entities based on it. In conjunction with RSpec, factories are usually stored in the spec / factories folder or directly in spec / factories.rb . For example, like this:

 Factory.define :user do |factory| factory.sequence(:email) { |i| "user#{ i }@example.org" } factory.password 'password' factory.password_confirmation { |user| user.password } factory.confirmed_at Time.now end 

Everything, now there is enough Factory (: user) in the tests and we have a lukewarm valid user.

Email Spec

https://github.com/bmabey/email-spec
You probably won't tell the name right away, but jam is used to test sending mail. Of course, it fits natively in both Cucumber and RSpec . In env.rb we write:

 require 'email_spec' # add this line if you use spork require 'email_spec/cucumber' 

In spec_helper.rb:

 require "email_spec" 

Further:

 $ rails g email_spec:steps 

Add auxiliary ready-made steps for tests.

Timecop

https://github.com/jtrupiano/timecop
This one I especially liked, allows you to travel through time. At first, he used something samopisnoe, and then came across this cop. It is irreplaceable when you need to check something tied up on time, for example, “ having put a pie in the oven, after waiting four hours, we get embers ”. Check out the article about him (in the list of references), there are steps for Cucumber . The only thing I would like to note is that over time it is better to mark tests with a special label (yes, those tags, both in Cucumber and RSpec ), for example, @travel_through_time in order to always return after them now, but then the tools will go crazy. I have the following lines in env.rb :

 After('@travel_through_time') do Timecop.return end 

The lines tell the cucumber to execute the code after each script with a corresponding label. In RSpec, you can do something similar.

Launchy

https://github.com/copiousfreetime/launchy
Sometimes it happens that the test falls (sometimes the same), and it is difficult to determine why. I would like to look at the page where, for example, Cucumber did not find the button “ Create ”. For these purposes, this jam is placed and in the steps of a cucumber it is added unevenly like:

 Then 'WTF?' do  save_and_open_page end 

Then simply in the script, we call the corresponding step before the one that does not pass, and we see in our browser a default saved page with the login form and the inscription “ You do not have permissions to perform this operation ”, something like that.

At the boot:% s / buggy / key / g


The environment is configured and ready to mock yourself to the fullest. Of course, there are no guarantees after this, that it will not remain just tuned, but will be actively used. Everything is in our hands, in general, everything, not just writing the letters of the code, all of life, mmm, yes. But, returning to BDD (I hope at least someone has looked at the conclusion of the decoding), I know by myself that until you force yourself to describe the behavior of the system in advance (and after that it's not bad either), you will not understand how important it is, but the main thing is convenient and useful. Now I don’t even have to open the browser to make sure that everything works, and especially when the rails heal all the brains of poor makosi. After such a development process, there are always features and specs that test some part of the functionality, which are then easy to run:

 $ rspec spec $ cucumber 

And here it will already become clear that you or your partner ... well done, in one word.
Thank you for your attention, I will write again if the subject touched the delicate strings of someone's quivering soul. Everything, it's time to sleep.

References (as in school)


About Cucumber :

About RSpec :

About Ryan Bates :

About Timecop :

About RVM :

About Git :

 // vim: set ft = habrahabr

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


All Articles