Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/archan937/gem_suit

Test the entire usage workflow (including generators) of your newly generated or existing gem within Rails 2 and 3.
https://github.com/archan937/gem_suit

Last synced: about 2 months ago
JSON representation

Test the entire usage workflow (including generators) of your newly generated or existing gem within Rails 2 and 3.

Awesome Lists containing this project

README

        

h1. GemSuit

Test the *entire* usage workflow (including the generators) of your newly generated or existing gem within Rails 2 and 3 and make the gem development mobile.

As Barney Stinson advises: *"Gem suit up! It's gonna be legend"* ^^

h2. Introduction

We Rails developers are experiencing great evolvements at the moment: not only are we migrating from Ruby 1.8 to Ruby 1.9, but we are also migrating from Rails 2.3 to Rails 3. This means that Rails gem writers have to deal with this. Luckily, there is "Rich-Support":https://github.com/archan937/rich_support which provides Rails 2 and 3 compliance to your Rails gem, but you also want to be able to run integration tests within a Rails 2 and 3 environment.

And so this is where GemSuit kicks in: it provides an extensive test suite to a (newly generated or existing) gem in which you can test the whole gem usage process. From a clean Rails (2 or 3) application, to running your gem generators, to testing your front-end within Firefox with Capybara.

GemSuit is "TestUnit":http://test-unit.rubyforge.org/, "Shoulda":https://github.com/thoughtbot/shoulda (mainly for contexts), "Capybara":https://github.com/jnicklas/capybara and "Selenium":http://seleniumhq.org/ driven and it also provides you to run the Rails (2 or 3) server and console (for development and testing purposes) very easily!

h3. So what can I test exactly?

As already mentioned, GemSuit really aims on testing the entire process of using your gem in a Rails app. A GemSuit integration test can consist of the following steps:

# Start with a clean Rails (2 or 3) application (as if you just ran @rails new your_rails_app@)
# Prep certain files (e.g. initializers) using Thor's template generation capabilities
# Run several generators provided by your gem
# Load fixtures
# Open the Rails app in the browser and run assertions (with Capybara in Firefox)

And also you can run unit tests (and the other standard tests) within both Rails 2 and 3.

A real world example of a GemSuit implementation is "Rich-CMS":https://github.com/archan937/rich_cms/tree/edge.

h2. Quickstart

Run the following in your terminal:


$ gem install gem_suit
$ suit tailor your_new_gem
$ cd your_new_gem
$ suit -v

*Note*: Make sure you have "Firefox":http://www.getfirefox.com installed.

h2. Installation

Run the following command in your console:


gem install gem_suit

h2. Provide your gem with GemSuit

h3. Generating a new gem

Run the following command to create a gem with Bundler and the GemSuit test suite:


suit tailor your_gem_name

*Note*: What @suit tailor@ actually does, is: @bundle gem your_gem_name@, @cd your_gem_name@, @suit up@ and finally @suit fit@.

h3. For an already created gem

Run the following command within your gem directory (e.g. in @Gems/rich_cms@ for the gem Rich-CMS)


suit up

Your gem is now provided with GemSuit ^^

h2. Great. But now what?

h3. Developing your gem

After you have made your gem a little bit more legend, you can start developing your gem with the Rails 2 and 3 dummy applications provided (within @suit/rails-{2,3}/dummy@). This makes the gem development very mobile as you can commit them (with the Sqlite databases) in your Git repository! Just run the following to start the Rails 3 server:


suit s

Run the Rails 2 server on port @3001@ as follows:


suit s -r2 -p3001

You can also start the Rails console (Rails 3 at default) of the dummy applications (use @-r2@ to use the Rails 2 console):


suit c

h3. Making your gem development mobile

It is possible that you will have to develop your gem on another computer or that there are multiple developers (and thus coping with different computers). As mentioned in the previous section, everything is added to the Git repository. The only pitfall can be that the computer is not prepped for the gem development. Think of not having all the gem dependecies installed.

Just check out the gem Git repository, install GemSuit and "fit the GemSuit" with @suit fit@. With "Rich-CMS":https://github.com/archan937/rich_cms/tree/edge as example, run the following:


$ git clone https://github.com/archan937/rich_cms.git
$ cd rich_cms
$ gem install gem_suit && suit fit -v

h2. Testing with GemSuit

h3. Running the GemSuit integration tests (with Capybara and Selenium)

To run the integration tests just run the following:


suit -v

*Note*: The @-v@ option outputs a summary of the test results. You can also run the tests with just @suit@ for no additional output or @suit -w@ for very verbose output.

h3. Restoring the Rails dummy applications

GemSuit uses the dummy applications for the integration tests by stashing and restoring its source files. When a test fails, the state of the Rails application directory stays as it is during the test. To reset the dummy application, just run the following command:


suit restore

h3. Running unit (and the common) tests with Rails 2 and 3

The standard Rails provided tests can be run with:


suit test unit

To only run tests in Rails 3, use the following:


suit test unit -r3

h2. Writing GemSuit integration tests

h3. A real world example

Please explore "https://github.com/archan937/rich_cms/tree/edge/suit":https://github.com/archan937/rich_cms/tree/edge/suit for examples of the GemSuit integration test possibilities.

h3. The provided ExampleTest

After running @suit up@ (or @suit tailor@ when creating a new gem), you will have @suit/shared/test/integration/suit/example.rb@ at your disposal. As you might have guessed, this is an example of a GemSuit integration test. You can see it in action by running:


suit -v

h3. Essential sources and directories

Certain sources (and directories) are essential when writing a GemSuit integration test:

h4. suit/shared/test/integration/suit/*.rb

   This directory contains all the GemSuit integration tests.
   At default it is provided with @example.rb@, "an example":https://github.com/archan937/rich_cms/tree/edge/suit/shared/test/integration/suit

h4. suit/shared/test/suit_application/==**/*.*==

   Source files within this directory will be required when running tests.
   You are supposed to put additional @lib@ sources for testing purposes in here: "an example":https://github.com/archan937/rich_cms/blob/edge/suit/shared/test/suit_application/rich/i18n_forgery.rb

h4. suit/shared/test/suit_application/capybara_extensions.rb

   This source file contains helper methods when running the GemSuit integration test with Capybara.
   Think of logging in, logging out and filling in a form: "an example":https://github.com/archan937/rich_cms/blob/edge/suit/shared/test/suit_application/capybara_extensions.rb

h4. suit/shared/test/suit_application.rb

   The role of @SuitApplication@ is to prepare and restore the dummy application when running a GemSuit integration test.
   Think of calling Rails generators, generating files with Thor and providing variables when compiling templates: "an example":https://github.com/archan937/rich_cms/blob/edge/suit/shared/test/suit_application.rb

h4. suit/shared/test/templates/==**/*.*==

   The templates used by SuitApplication (and thus Thor) when generating files for test preparations.
   You can write shared / Rails 2 specific / Rails 3 specific templates, "an example":https://github.com/archan937/rich_cms/tree/edge/suit/templates

h3. A GemSuit integration test

It is actually a simple @ActionController::IntegrationTest@ which requires @suit_application.rb@ instead of the regular @test_helper.rb@.
Also, two methods of @SuitApplication@ are called:

* @SuitApplication.test@ - Prepare the Rails dummy application for a certain environment (you can pass options to @SuitApplication@)
* @SuitApplication.restore_all@ - Restore the Rails dummy application source files after running the integration test

The basic structure:


require File.expand_path("../../../suit_application.rb", __FILE__)

SuitApplication.test :some => :variable

class YourGemSuitIntegrationTest < GemSuit::IntegrationTest

context "My example test" do
setup do
# prepare something
end

teardown do
SuitApplication.restore_all
end

should "pass" do
# visit some pages
# click some links and fill in some forms
# assert some statements
end
end

end

h3. SuitApplication class

This class prepares and restores the Rails dummy application when running a GemSuit integration test. You can leave it as is, but that wouldn't be fun.

*Note*: See "https://github.com/archan937/rich_cms/blob/edge/suit/shared/test/suit_application.rb":https://github.com/archan937/rich_cms/blob/edge/suit/shared/test/suit_application.rb for a real world example.

The following examples are combination with this GemSuit integration test:


require File.expand_path("../../../suit_application.rb", __FILE__)

SuitApplication.test :authentication => :devise

class YourGemSuitIntegrationTest < GemSuit::IntegrationTest
...

h4. Describe your test

This is the description used for a reference to the integration test. At default, GemSuit derives it based on the file name of the integration test.


def description
case authentication
when :devise
"Devise authenticated"
else
"Non-authenticated"
end
end

h4. Prepare your Rails dummy application with Thor

This is where you are supposed to run your generators and generate files using templates. You can also prevent source files from automatically included (which is the case for @test/suit_application/*.rb*@).


def prepare
case config[:authentication]
when :devise
generate_devise_user
correct_devise_config
end
skip :require, "test/suit_application/rich/i18n_forgery.rb"
end

def locals_for_template(path)
case path
when "the/path/to/a/certain/template"
{:some_template_variable => "some_value"}
end
end

private

def generate_devise_user
generate "devise:install"
generate "devise", "User"
end

def correct_devise_config
devise_config = expand_path("config/initializers/devise.rb")
lines = File.open(devise_config).readlines
pepper = "a26c248ff40b12f4e396c1d33168408e2f442c3b6288df70ca46c340db3f1f2f7aa80ec37867ddfd602a185deda0b5efb27ecd8f7541b97d7c02e9485bbb57fd"

log :correcting, devise_config
File.open(devise_config, "w") do |file|
lines.each do |line|
file << line.gsub(/(config\.pepper = ").*(")/, "config.pepper = \"#{pepper}\"")
end
end
end

h4. Stash and restore files

As you might have guessed, files are being stashed *before* testing and restored *after* testing.


def restore_files
delete "config/locales/devise.en.yml"
delete "db/migrate/*.rb"
delete "test/fixtures/devise_users.yml"
delete "test/unit/devise_user_test.rb"
end

def stash_files
delete "db/migrate/*.rb"
stash "app/models/*.rb"
stash "config/initializers/devise.rb"
end

h3. Capybara extensions

You can define helper methods for the integration tests when running with Capybara in @capybara_extensions.rb@.
Think of actions such as logging in, logging out and filling in forms:


module GemSuit
class IntegrationTest

def login
visit "/cms"
page.execute_script "$('div#rich_cms_dock a.login').click()"
fill_in_and_submit "#raccoon_tip", {:Email => "[email protected]", :Password => "testrichcms"}, "Login"
end

def logout
find("#rich_cms_dock").click_link "Logout"
end

def mark_content
page.execute_script "$('div#rich_cms_dock a.mark').click()"
end

def edit_content(key, css_class = "rcms_content")
page.execute_script <<-JAVASCRIPT
$(".#{css_class}.marked[data-store_key=#{key}]").click();
JAVASCRIPT
assert find("#raccoon_tip").visible?
end

def fill_in_and_submit(selector, with, submit)
within "#{selector} fieldset.inputs" do
with.each do |key, value|
begin
fill_in key.to_s, :with => value
rescue Selenium::WebDriver::Error::ElementNotDisplayedError
page.execute_script <<-JAVASCRIPT
var input = $("#{selector} [name='#{key}']");
if (input.data("cleditor")) {
input.val("#{value}");
input.data("cleditor").updateFrame();
}
JAVASCRIPT
end
end
end
find(selector).find_button(submit).click
sleep 2
end

end
end

h2. Writing the "common" unit tests

The unit tests have to be located within @suit/shared/test/unit/@. Run the tests as mentioned earlier with @suit test unit@.

h2. Getting more info with Thor

As the GemSuit command line interface (CLI) is built with "@wycats":http://twitter.com/wycats "Thor":https://github.com/wycats/thor gem, you can use the @suit help@ command in your terminal:


$ suit help
Tasks:
suit bundle # Run `bundle install` (should be invoked from a Rails dummy application) only when necessary (used for testing)
suit config [global] # Configure GemSuit within your gem (use `suit config global` for global config)
suit console [ENVIRONMENT] # Start one of the GemSuit test application consoles
suit fit # Establish the GemSuit in your environment
suit help [TASK] # Describe available tasks or one specific task
suit restore # Restore all files within the GemSuit test applications
suit server [ENVIRONMENT] # Start one of the GemSuit test application servers
suit tailor NAME # Generate a Bundler gem and provide it with GemSuit
suit test [SECTION] [FILES] # Run GemSuit (suit, unit, functional, integration) tests
suit up # Provide an existing gem with GemSuit

To get info about the options of a command, narrow the output to that command. Just type @suit help @:


$ suit help server
Usage:
suit server [ENVIRONMENT]

Options:
-p, [--port=PORT]
-r, [--rails-version=RAILS_VERSION]

Start one of the GemSuit test application servers

h2. So where are the tests?

As GemSuit is very focused on the command line and file generation, it is hard (but not impossible) to write tests. So therefore my test case is the entire "Rich-CMS":http://github.com/archan937/rich_cms gem. I am using GemSuit for all of its development and testing purposes.

h2. Contact me

For support, remarks and requests please mail me at "[email protected]":mailto:[email protected].

h2. License

Copyright (c) 2011 Paul Engel, released under the MIT license

"http://holder.nl":http://holder.nl – "http://codehero.es":http://codehero.es – "http://gettopup.com":http://gettopup.com – "http://twitter.com/archan937":http://twitter.com/archan937 – "[email protected]":mailto:[email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.