Средства тестирования в Ruby on Rails

Как известно, тестирование является одной из важнейших составляющих разработки приложений на основе Ruby on Rails. Поддержка тестирования была включена в Rails с самого начала, для этого использовалась библиотека Test::Unit. Однако, со временем, появилось много альтернативных средств для тестирования в Rails-приложениях.

В этой заметке я проведу небольшой обзор средств, используемых в настоящий момент для тестирования приложений на базе Ruby on Rails. Я не ставлю себе целью выбрать “лучшее” – я считаю, что этот выбор должен делать каждый сам, однако я попытаюсь показать различные варианты – чтобы было из чего выбирать.

Модульные и функциональные тесты

Здесь я рассмотрю основные средства, используемые для модульного и функционального тестирования в Rails-приложениях. Напомню, что модульные тесты используются для тестирования логики приложения, которая расположена в моделях, а также для тестирования различных независимых участков приложения, например, хелперов (helpers).

Test::Unit

Test::Unit является классическим средством тестирования в стиле xUnit. В Rails-приложениях именно он и используется по умолчанию. Набор тестов с его использованием описывается в виде класса, методы которого представляют различные тесты. В коде методов в необходимых точках добавляются проверки, представленные вызовами assert_*.

Ниже приведен пример простейшего теста с использованием Test::Unit:

require 'test/unit'

class MyTest < Test::Unit::TestCase
  # def setup
  # end

  # def teardown
  # end

  def test_fail
    assert(2 + 2 == 4, 'Assertion was false.')
  end
end

RDoc-документация для Test::Unit: http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html

RSpec

RSpec - средство, предназначенное для спецификации поведения кода. Я не хочу вдаваться в отличия спецификации от тестирования (и BDD от TDD), просто приведу пример спецификации модели с использованием RSpec:

describe "A new account" do

  before do
    @account = Account.new
  end

  it "should have a balance of $0" do
    @account.balance.should eql(Money.new(0, :dollars))
  end

end

Как видно из примера, RSpec представляет специальный язык в рамках Ruby для описания спецификаций. Следствием этого является то, что хорошо написанные спецификации легко читаются, практически как текст на английском языке.

Одним из минусов RSpec является то, что для проверки спецификаций требуются создавать специальные Rake-задачи в приложении, в отличии от тестов на основе Test::Unit, задачи для которого включены в Rails.

Сайт проекта: http://rspec.info

RDoc-документация для RSpec: http://rspec.rubyforge.org/rspec/1.2.8/

Test/Spec

Test/Spec предназначен для описания спецификаций, аналогичных RSpec на базе Test::Unit, что позволяет использовать те же самые стандартные задачи, что и для Test::Unit, а также совмещать тесты и спецификации.

require 'test/spec'

describe "Foo" do
  it "should bar" do
    (2 + 3).should.equal 5
  end
end

Сайт проекта Test/Spec и RDoc-документация: http://test-spec.rubyforge.org/

Shoulda

Shoulda - это средство, которое работает на базе Test::Unit и предоставляет некоторые дополнительные возможности, в частности специальный язык для описания конструкций в тестах и набор макросов для часто используемых проверок:

class UserTest < Test::Unit::TestCase

  should_have_many :posts

  should_not_allow_values_for :email, "blah", "b lah" 
  should_allow_values_for :email, "a@b.com", "asdf@asdf.com" 
  should_ensure_length_in_range :email, 1..100
  should_ensure_value_in_range :age, 1..100
  should_protect_attributes :password

  context "A User instance" do
    setup do
      @user = User.find(:first)
    end

    should "return its full name" do
      assert_equal 'John Doe', @user.full_name
    end

    context "with a profile" do
      setup do
        @user.profile = Profile.find(:first)
      end

      should "return true when sent #has_profile?" do
        assert @user.has_profile?
      end
    end
  end
end

Update: В настоящий момент Shoulda может быть использована и вместе с RSpec

Сайт проекта: http://www.thoughtbot.com/projects/shoulda/

Remarkable

Shoulda показала удобство использования макросов для распространенных задач в тестировании, однако она работала только над Test::Unit. Remarkable - это реализация набора макросов, аналогичных Shoulda для RSpec. Его использование позволяет описывать следующие спецификации:

describe Post do
  it { should belong_to(:user) }
  it { should have_many(:comments) }
  it { should have_and_belong_to_many(:tags) }

  it { should validate_presence_of(:body) }
  it { should validate_presence_of(:title) }
  it { should validate_uniqueness_of(:title, :allow_blank => true) }
end

Сайт проекта Remarkable и RDoc-документация: http://remarkable.rubyforge.org/

Блог проекта: http://www.nomedojogo.com/category/remarkable/

Исходный код Remarkable: http://github.com/carlosbrando/remarkable/tree/master

Интеграционные тесты - Cucumber

Cucumber, используемый для интеграционного тестирования приложений продолжает движение в сторону читабельности тестов - тестовые сценарии описываются буквально на естественном языке:

  Scenario: Add two numbers
    Given I have entered 13 into the calculator
    And I have entered 22 into the calculator
    When I press "+"
    Then the result should be 35 on the screen

И не только на английском:

  Сценарий: Сложение двух целых чисел
    Допустим я ввожу число 50
    И затем ввожу число 70
    Если я нажимаю "+"
    То результатом должно быть число 120

Написание сценариев в таком виде делает Cucumber просто незаменимым инструментом для тестирования Rails-приложений. Разумеется, некоторое количество кода писать все-таки приходится, для того чтобы описать что означают те или иные приложения.

Заключение

Здесь я описал некоторые средства, используемые для тестирования Rails-приложений. Я сознательно не затрагивал здесь различные библиотеки для создания mock-объектов или замены fixtures, возможно, в дальнейшем им можно посвятить отдельную заметку.

 Подписаться на RSS

 #  #  #  #  #  #  #  #  #  #

Комментарии

  1. Мне так кажется, или кода как то не хватает.

  2. Уже решил проблему - вырубил js.

  3. Хочется дополнить, что шулда прекрасно умеет работать с rspec.

  4. Спасибо за информацию, добавил.

  5. В самом деле, мне не совсем ясно, зачем использовать Remarkable, если есть Shoulda. Но это на любителя, в Remarkable есть очень красивый и элегантный метод писать спеки на контроллеры.

Добавить комментарий