shoulda: running concrete context

5 мая 2009, Вторник

Многие Rails разработчики уже используют shoulda - замечтельный  BDD фреймворк от команды thoughtbot, как альтернативу rspec, например.

Сам фреймворк - это надстройка над UnitTests.

При разработке с  UnitTests часто возникает необходимость запустить отдельный тест и посмотреть результаты. Но как быть с shoulda - ведь названия тестов здесь это обычные текстовые предложения, которые формируются с учетом контекста теста и контекстов в котором тест находится. Например:

require File.dirname(__FILE__) + '/../test_helper'
require 'shoulda'

class ArticleTest < Test::Unit::TestCase
  fixtures :all
  context "On create" do
    should "create article if all params ok" do
      article = Article.new( :title => "shoulda rocks", :body => "Try it")
    end
    should "require title" do
      article = Article.new(:body => "That article wouldn't be published")
    end
    should "require body" do
      article = Article.new(:title => "Where is my body?")
    end
  end
end

В таком случае shoulda сгенерит следующие тесты:

test: On create should create article if all params ok
test: On create should require title
test: On create should require body

Пока у нас не много тестов все ок. Но если у нас большое количество контекстов, например, On Create, On  Update, On Destroy и т.д.? И мы хотим выполнить определенный контекст для того чтобы понять где именно проблема.

Для этого воспользуемся возможностью UnitTests запускать отдельные тесты с ключем -n

Test::Unit automatic runner.
Usage: test/unit/shop_test.rb [options] [-- untouched arguments]

    -r, --runner=RUNNER          Use the given RUNNER
                                 (c[onsole], f[ox], g[tk], g[tk]2, t[k])
    -n, --name=NAME              Runs tests matching NAME.
                                 (patterns may be used).
    -t, --testcase=TESTCASE      Runs tests in TestCases matching
                                 TESTCASE. (patterns may be used).
    -I, --load-path=DIR[:DIR...] Appends directory list to $LOAD_PATH.
    -v, --verbose=[LEVEL]        Set the output level (default
                                 is verbose). (s[ilent],
                                 p[rogress], n[ormal],v[erbose])
        --                       Stop processing options so that the
                                 remaining options will be passed to the
                                 test.
    -h, --help                   Display this help.
Deprecated options:
        --console                Console runner (use --runner).
        --gtk                    GTK runner (use --runner).
        --fox                    Fox runner (use --runner).

Как показывает нам справка, параметром ключа -n может быть любое регулярное выражение. Например, команда:

ruby test/unit/article_test.rb --name="/test:(.*)On create(.*)/"

запустит на выполнение только тесты из контекста On create.

Вот так вот.

MySQL MyISAM + rails tests = bugs

29 апреля 2009, Среда

Пришлось мне на днях потюнить MySQL. Решил попробовать разные конфигурации на предмет максимальной производительности по моим задачам. Нарыл ряд статей по  улучшению производительности. Лучше всего ИМХО написано было сдесь.

Пред история. Сразу скажу что запросы у меня простые и короткие. Пара селектов по индесированым полям + инсерт + апдейт. Ничего сложного. Но! В один прекрасный момент СУБД просто брала и начинала жрать все ресурсы процессора как локально так и на продакшин сервере. Однодневный инвестигейт показал интересную вещь. После инсерта происходит перестрой индексов данной таблицы, что само по себе требует ресурсов процессорного времени и это время прямо пропорционально количеству записей в таблице. Таким образом, если мне нужно много циклов записей/селектов подряд то время каждого цикла начинает расти. И у меня оно дошло до 1го цикла в секунду. Это при том что мне нужно это сделать 300к-500к раз. Посчитав примерно во что мне это обойдется вышло что весь цикл будет длиться с недельку. Это естественно ни в какие рамки не лезет.

Посему начал рыть. Сначала в сторону тюнинга СУБД. В целом добился прироста производительности гдето на 10%. Но проблема как обычно была не в СУБД. Т.е. как-бы в СУБД но не в СУБД. В общем это не самое интересное.

Самое интересно это то, что вовремя тюнинга я настроил все базы на использования движка MyISAM. И тут начались спец-эффекты. Упало ряд тестов. Анализ кода ничего не показал. Анализ фикстур, откаты изменений (я работаю в команде посему начал грешить на последние комиты) все это ни к чему не привело.

Начал думать (гуглом). Как оказалось тесты в рельсах работают (в основном) в режиме транзакций. Т.е. каждый тестовый случаю выполняется как транзакция, которая потом (после выполнения тестового случая) откатывается. Теперь о MyISAM, как извесно этот движек не поддерживает транзакций, поэтому ряд тестов модифицируют данные необратимо. С этим и были связаны глюки. Кроме того, глюки будут также если у вас есть модифицирующие хранимые процедуры.

Вердикт. Для тех кто использует MySQL в тестовых версиях используйте движек InnoDB, иначе могут выпасть очень даже интересные глюки. Или используйте PostgreSQL.

Блог работает на WordPress.
Подписка RSS: все записи, комментарии.