Using modules and methods within specs
I’m pretty sure that by now you have been thinking along the lines - “Oh, wait! There’s going to be a lot of code duplication when creating more than one spec file”. That is not good at all because it causes more pain when trying to maintain your code. RSpec is built to be able to practice DRY principles. So, let’s see from the current spec file, what will be needed in all (or most) spec files. Of course before and after blocks will be repeated in most of the spec files. There might be something different for some spec file, but usually those blocks are quite similar for all spec files throughout the application. I’m going to deal with this duplication later on - there’s one quite nifty feature of RSpec which solves this kind of problems. So, what’s left? There’s some methods, which will probably be used also throughout the specs like set_browser_for_rspec and formatter. There’s going to be probably some more methods like these - some method for logging user into the application, some method to log out and another methods which do some common things for your application under test.
As some of you hopefully already noticed then there’s the possibility to create methods within the describe block. That is also used to keep your spec files DRY. You could of course use the same code in every it block without extracting this common code into methods but that would be just plain stupid. Think what is going to happen if business logic for logging user into the application changes - this means that you’d have to change all your spec files also to use the new business logic, but if you have extracted this functionality into some method then you’d just need to change it from one place. The main point for this is that as soon as you notice that you’re using some code at more than one place then you should move that code into method and call the method instead.
Here’s one example of using methods within describe block in spec:
As you can see then i’ve extracted some specific logic into methods called setup, check_for_errors, open_browser_at and log_in. While reading the actual test itself then it should be quite readable. Even more readable actually because now it’s possible to give meaningful names for your methods so no-one needs to think what you’re trying to accomplish by filling in all the text fields when the method name is log_in. That’s the additional benefit. But still the spec looks kind of messy and what happens if you create second spec file where you have to also use these or some of these methods? The answer to this question is Ruby’s modules. Let’s extract all of the methods above into the module:
And now you can move this MyHelper module into separate file - let’s call it as a my_helper.rb and add require “my_helper” statement into your spec file. This gives you the ability to create common methods and extract them into the modules and then just use these modules in your specs without having to create any code duplication! You can also nest modules within eachother:
As you can see then this also gives you the possibility to move some of the require statements into more top-level so you won’t have to load spec and watir in each file (actually it won’t load anyway since Ruby knows that they’re already loaded, but it just reduces the amount of code you need to have in your spec files).
In other words you should have some global helper module which has methods for global use and are not specific to the application under test and you should have some specific modules for your application. You can have multiple modules to keep methods specific to the application’s different behaviour or functionality separated.
Usually when i’m extracting some of the code into the methods in my spec files then i won’t create a module right away if i’m not sure that this code would be usable at somewhere else. I will create a module nevertheless if there’s going to be more than a few methods in my describe block just to keep the spec itself more clean of the “noise” - but this time the module will be just specific to my spec file and doesn’t have any higher purposes.
Let’s keep our code DRY so everyone will be happy! You can see the changes i made to the original spec file at GitHub.




2 years ago