julik live

Rails fixtures и машина времени

Fixtures - это способ в удобном текстовом формате (CSV или YAML) собирать тестовые записи для тестирования Rails-приложения. У такого способа тестирования есть недостаток по скорости (поскольку в базу при каждом прогоне тестов данные загружаются заново), но есть и ряд преимуществ - можно тестировать реальные SQL-выборки.

Стандартный файл с fixtures выглядит так:

 first_comment:
   id: 1
   from: Joe User
   created_on: 2001-10-02

 second_comment:...

и так далее. Тем не менее, иногда полезно воспользоваться ERB - Embedded Ruby - для генерации данных, зависимых от среды, в которой проводятся тесты. Благодаря тому, что при каждом прогоне тестов шаблон рендерится заново, можно пользоваться полезными свойствами языка чтобы сделать fixture гораздо более понятной при чтении.

Например, предположим, что в базе есть пароли, закодированные как MD5:

  main_site:
    id: 1
    name: Blogue
    admin_password: 5ebe2294ecd0e0f08eab7690d2a6ee69
    admin_email: authors@blog.ru
    approves_comments: 0

При использовании ERB это легко можно заменить на пароль в "естественном виде":

  main_site:
    admin_password: <%= MD5.new('secret') %>

Но это скорее удобство. А вот где это совершенно незаменимо - так это в работе с датами и временем. К примеру - нам нужно показывать только сообщения, появившиеся на сайте за последнюю неделю. А в файле с fixtures мы укажем их больше - например пяток, из которых два сообщения размещены раньше. Поскольку у базы и системы в целом время работает когерентно, тестировать такие данные крайне неудобно. В решении этой проблемы больше всего помогает ERB.

Имейте в виду, что тобы база восприняла текст как корректную дату или время надо применять очень четкое их форматирование.

Например, сообщение, которое только будет размещено в базе через 10 дней:

published_on: <%= (10.days.from_now).to_date %>

Или сообщение, размещенное год назад (методы year/seconds возвращают целое число, обозначающее количество секунд, конструкции ago и from_now вычисляют исходя из них абсолютное время в обьекте Time):

published_on: <%= (1.year.ago).to_date %>

Вызов to_date необходимо делать, чтобы данные были сконвертированы в формат даты а не времени (иначе MySQL не воспримет их как корректную дату и проставит ее вам в 0000-00-00).

Cо значениями времени (поле datetime) схема немного другая - для него самым обещупотребительным (и в частности используемым в ATOM и RSS) является формат ISO 8601 с целым рядом достоинств - фиксированная длина, учет временной зоны и так далее. Заодно этот формат будет адекватно воспринят базой данных. Поэтому для выражения в fixtures времени применяется метод iso8601, добавляемый Рельсами к обьектам Time. Например, вот как мы бы выразили в fixtures объект "заказа аренды некоего устройства на 10 дней, начинающейся через месяц".

booking:
  id: 2
  client_id: 2
  device_id: 1
  confirmed: 1
  starts: <%= (1.month.from_now).iso8601 %>
  ends: <%= (40.days.from_now).iso8601 %>

Альтернативно можно вызывать to_s(:db)

В итоге такой обьект всегда при занесении в базу будет иметь значения, соответствующие системному времени и начинающиеся через месяц и 40 дней соответственно.

Машина времени.

Suspects: Веб-стройка

 
comments powered by Disqus

Aspirine not included.