Тестирование: зачем бесконечные моки, стабы и т.п.?

1,124 views
Skip to first unread message

Max Lapshin

unread,
Aug 18, 2015, 6:59:50 AM8/18/15
to RubyOnRails to russian
Коллеги, у меня вопрос насчёт тестирования.

Мы в эрливидео в процессе разработки видеостримингового сервера полностью отказались от использования моков в каком либо виде.

Если нужно протестировать, как наш софт ходит куда-то по HTTP, то поднимается HTTP сервер, в нём описываются нужные урлы и наш софт ходит к настоящему http серверу.

Если надо что-то запросить по HTTP с нашего сервера, то мы в тесте запрашивает по HTTP и проверяем то, что протекло по сокету.

Это очень правильный подход, потому что мы проверяем полностью весь стек. Плюс в эрланге сходить куда-то по HTTP очень быстро, так что на скорость тестов это не влияет. Дополнительно к этому у нас прогоняется до 100 параллельных тестов, которые интерферируют друг с другом и это тоже очень правильно и полезно.


В рельсах я вижу странную культуру: вместо реальных запросов идут постоянные стабы да моки, которые пропускают солидное количество ошибок.

Почему так? Только из-за того, что это ускоряет прогон тестов? Или тут вопрос в подходе к тестам? 

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

Тут что ли по-другому принято?


Илья Плотников

unread,
Aug 18, 2015, 7:24:04 AM8/18/15
to ror...@googlegroups.com
Так оно одно другое не исключает. Одно функциональное, другое интеграционное. На какое делать упор, подскажет принцип целесообразности

18.08.2015 13:59, Max Lapshin пишет:
--
--
Данное сообщение отправлено Вам, так как Вы являетесь подписчиком группы "RubyOnRails to russian" на https://groups.google.com/group/ror2ru
FAQ группы находится по адресу: http://ru.wikibooks.org/wiki/RubyFAQ
 
Для того, чтобы отправить сообщение в эту группу, пошлите его по адресу
ror...@googlegroups.com
---
Вы получили это сообщение, поскольку подписаны на группу "RubyOnRails to russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес ror2ru+un...@googlegroups.com.
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/ror2ru/CAMxVRxAwwCYwALbGHA36%2BxO0Upp_bFkG0zB%3DUxf2xc9gUBuzOQ%40mail.gmail.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

-- 
Всегда Ваш, Илья Плотников

Max.L...@gmail.com

unread,
Aug 18, 2015, 7:38:47 AM8/18/15
to RubyOnRails to russian
Вдогонку ещё вопрос:

а как вообще в рельсовых спеках сделать параллельное обращение к нескольким сессиям, сэмулировав параллельную работу двух разных юзеров в одном тесте?

describe “making trials” do

  s1 = new_session

  login_user(s1, “admin@localhost”, “password”)

  s2 = new_session

  s2.post(“/create_trial”, ….).expect ...

  response =  s1.get “/trials”

  response.expect ….

  s1.post(“/accept_trial”).expect …

  mailers.expect …

  s2.get("/trial").expect(...)

end



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


Насчёт целесообразности я то для себя решил =)  У нас вся наша серверная часть проекта достаточно сильно сервисно организована, около 7 независимых несвязанных проектов, так что мы новый проект будем закрывать именно высокоуровневыми тестами. 


Victor 'Zverok' Shepelev

unread,
Aug 18, 2015, 7:41:18 AM8/18/15
to ror...@googlegroups.com
Погоди, то есть если бы ты делал, условно говоря, клиент к API Facebook, ты бы поднял локальный HTTP-сервер, изображающий поведение API Facebook, включая всякие аутентификации, рейт-лимиты и проч.?..

18 августа 2015 г., 13:59 пользователь Max Lapshin <max.l...@gmail.com> написал:

Сергей Соколов

unread,
Aug 18, 2015, 7:42:40 AM8/18/15
to ror...@googlegroups.com
Ну у нас порядка 700 тестов, если мы в каждом из них начнем тригать всякие пересборки статистики, обращения к внешним сервисам итд - они будут проходить несколько часов. 

Сейчас, максимально используя моки, и оставляя лишь несколько интеграционных тестов для проверки, что формат общения между модулями не изменился, они в целом проходят за 7 минут, но правя какой-то один модуль, я при разработке, запускаю только его тесты и уверен, что тестируется именно происходящее внутри него, и проходят они очень быстро. 

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

Кроме того, при независимых тестах у вас валится только то, что реально сломано, а не все, что на него подвязано. 

PS Разрабатывая через тесты вообще не понимаю, как можно делать только высокоуровневые тесты, когда модуль пишется по спецификации входных и выходных данных от других модулей, которые обычно вообще еще не существуют.

PSS Думаю, подход к тестам максимально зависит от приложения, которое они тестируют, если у вас получается держать только высокоуровневый - это же классно! :)

18 августа 2015 г., 13:59 пользователь Max Lapshin <max.l...@gmail.com> написал:
Коллеги, у меня вопрос насчёт тестирования.

Max.L...@gmail.com

unread,
Aug 18, 2015, 7:54:17 AM8/18/15
to RubyOnRails to russian
Да, я бы сделал http-сервер иммитирующий фейсбук, потому что это задача аналогичная по сложности обвешиванию стабами запросы к фейсбуку.

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


У нас сейчас в системе (на эрланге) чуть больше 1000 тестов, из них примерно 200 делает порядка нескольких сотен HTTP вызовов наружу. Т.е. в переводе на тот стиль, который есть в мануале каких-нибудь thoughtbot, это наверное порядка 10 тыс тестов. Это всё проходит по happy path за полторы минуты, включая куски транскодирования видео (CPU улетает в топ), реальной записи архива на диск и перегонки нескольких сотен мегабайт с диска.

Для рельс такая производительность недостижима? Или просто не получается запускать тесты параллельно?


Я понимаю что высокоуровневый подход может привести к комбинаторному взрыву, но это мы решаем такими же комбинаторными тестами и опять же: это оказалось гораздо более продуктивным вариантом, поскольку не создает ложной иллюзии надежности системы, когда отдельные модули потестированы, а всё вместе не работает. Рекомендую так попробовать: описываете пространство условий, делаете функцию, которая заполняет все элементы этого пространства и тестируете автоматически каждый вариант.






Max Lapshin

unread,
Aug 18, 2015, 8:11:57 AM8/18/15
to RubyOnRails to russian
Сергей, у вас реально 7 минут гоняются 700 тестов?

А чего там происходит? Вы пытались разобраться? Мне кажется, это серьезная помеха в работе, потому что очень сильно отвлекаешься во время прогонки тестов.


Сергей Соколов

unread,
Aug 18, 2015, 8:27:16 AM8/18/15
to ror...@googlegroups.com
Там даже пытаться не надо - у нас много статистики собирается через api/парсингами - так вот даже если не брать в расчет парсинги, апи может вертать статистику около минуты вообще спокойно, втч у яндекса. А совсем до конца замокать нельзя - ибо они могут это апи изменить никого не предупредив вообще. В итоге получается делаешь 1 тест на то, что все еще приходят правильные данные, а потом куча тестов с моками данных, чтобы протестить что с этими данными уже должно делаться на момент сбора.

18 августа 2015 г., 15:11 пользователь Max Lapshin <max.l...@gmail.com> написал:
Сергей, у вас реально 7 минут гоняются 700 тестов?

А чего там происходит? Вы пытались разобраться? Мне кажется, это серьезная помеха в работе, потому что очень сильно отвлекаешься во время прогонки тестов.


--
--
Данное сообщение отправлено Вам, так как Вы являетесь подписчиком группы "RubyOnRails to russian" на https://groups.google.com/group/ror2ru
FAQ группы находится по адресу: http://ru.wikibooks.org/wiki/RubyFAQ
 
Для того, чтобы отправить сообщение в эту группу, пошлите его по адресу
ror...@googlegroups.com
---
Вы получили это сообщение, поскольку подписаны на группу "RubyOnRails to russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес ror2ru+un...@googlegroups.com.
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/ror2ru/CAMxVRxCRbg2kUENL0%3DnsT7YOohVnTixHePh5QCWbSoKRZdtMfA%40mail.gmail.com.

Max Lapshin

unread,
Aug 18, 2015, 8:31:57 AM8/18/15
to RubyOnRails to russian
Т.е. ты пользуешься API яндекса не через http, а через их SDK?

И этот SDK мокаешь?

Сергей Соколов

unread,
Aug 18, 2015, 8:38:13 AM8/18/15
to ror...@googlegroups.com
У нас своя обертка из функций написана, которая забирает, что нам надо и переделывает в Hash - вот этот метод мокаю, который hash отдает и отдаю тестовые подделанные данные, которые нужны уже.

18 августа 2015 г., 15:31 пользователь Max Lapshin <max.l...@gmail.com> написал:
Т.е. ты пользуешься API яндекса не через http, а через их SDK?

И этот SDK мокаешь?

--
--
Данное сообщение отправлено Вам, так как Вы являетесь подписчиком группы "RubyOnRails to russian" на https://groups.google.com/group/ror2ru
FAQ группы находится по адресу: http://ru.wikibooks.org/wiki/RubyFAQ
 
Для того, чтобы отправить сообщение в эту группу, пошлите его по адресу
ror...@googlegroups.com
---
Вы получили это сообщение, поскольку подписаны на группу "RubyOnRails to russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес ror2ru+un...@googlegroups.com.
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/ror2ru/CAMxVRxAJMosQA3HEYj2QVs65fwzaD7w3w6xoJ6yaehFcPJOOZA%40mail.gmail.com.

Max Lapshin

unread,
Aug 18, 2015, 8:48:04 AM8/18/15
to RubyOnRails to russian
А большого размера эти 700 тестов?

Параллельно их не запустить?

Евгений Лихолетов

unread,
Aug 18, 2015, 8:48:24 AM8/18/15
to RubyOnRails to russian
Юнит тесты нужны, чтобы максимально быстро локализовать проблему. Если сломался интеграционный тест, мест для поиска бага может быть с десяток. Если сломался юнит — обычно сразу очевидно где копать. Моки/стабы нужны для того, чтобы тестировать именно юнит, а не всю обвязку и не внешний сервис.

В рельсах принято юнит-тестировать нетривиальные модули, а для высокоуровневых интеграционных тестов есть VCR. И не надо никакие сервера для тестирования поднимать=)

вторник, 18 августа 2015 г., 13:59:50 UTC+3 пользователь Max.L...@gmail.com написал:

Max Lapshin

unread,
Aug 18, 2015, 8:58:54 AM8/18/15
to RubyOnRails to russian
Весь вопрос с тестами заключается в том: сколько тестов надо будет переписать и поправить через полгода, когда захочется поправить баг в дизайне внутри системы.

Чем более высокоуровневы тесты, тем меньше их надо регулярно править. Юнит тесты прийдется выкинуть в гораздо большем объёме, а это значит, что вся информация по багам будет уничтожена.


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

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


VCR мне притащил в проект один человек. Все эти рекординги пошли в помойку в первый же месяц, очень хрупкая конструкция, мне не понравилось.





Евгений Лихолетов

unread,
Aug 18, 2015, 9:10:56 AM8/18/15
to RubyOnRails to russian
Юнит-тесты и код ходят парой, переписываешь код, меняешь реализацию — меняй и тесты. Такова цена. Никто же не жалуется, что надо переписывать код при рефакторинге.

Высокоуровневые тесты, по большей части, регрессионные. Юнит-тесты больше нужны для TDD и дебага в процессе разработки модуля. Я, например, слабо себе представляю как писать какой-нибудь модуль парсинга или трансляции данных из одного формата в другой, использую только высокоуровневые тесты.
Если тестирование в разработке не используется и тесты нужны только для отлова свежих багов перед деплоем — вопросов нет, можно обойтись только Капибарой.

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

вторник, 18 августа 2015 г., 15:58:54 UTC+3 пользователь Max.L...@gmail.com написал:

Max Lapshin

unread,
Aug 18, 2015, 9:12:42 AM8/18/15
to RubyOnRails to russian
В целом концепцию понял =)

Видимо, это общий подход, иначе чем ещё объяснить такую нищету практики высокоуровневого тестирования. Я немного удивлен тому, что мне сейчас в 2015 году прийдется писать самому обвязку для тестов.

Alexey Bondar

unread,
Aug 18, 2015, 1:18:35 PM8/18/15
to ror...@googlegroups.com
On 18 Aug 2015, at 14:46, Евгений Лихолетов <bsb...@gmail.com> wrote:

Юнит тесты нужны, чтобы максимально быстро локализовать проблему. Если сломался интеграционный тест, мест для поиска бага может быть с десяток. Если сломался юнит — обычно сразу очевидно где копать. Моки/стабы нужны для того, чтобы тестировать именно юнит, а не всю обвязку и не внешний сервис.


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


On 18 Aug 2015, at 15:10, Евгений Лихолетов <bsb...@gmail.com> wrote:

Юнит-тесты и код ходят парой, переписываешь код, меняешь реализацию — меняй и тесты. Такова цена. Никто же не жалуется, что надо переписывать код при рефакторинге.

Раз уж разговор зашел о цене. Изолью свою боль в чятик.

Первая вещь в которой стоит себе признаться — тесты ничего не гарантируют. 

Даже если у вас 100% покрытие тестами по версии некоторой пузомерки, это ничего абсолютно не гарантирует, кроме того, что в протестированных путях логика одного приложения (продукт) соответствует ожиданиям другого (автоматические тесты). Тесты не Нарния, в которой магическим образом перестаёт работать человеческий фактор. Ошибки в тестах нормальное дело.

Вместе с магией зелёных циферок-галочек в CI это даёт ложную уверенность в «надёжности» продукта, которая имеет настолько сильный психологический эффект что все забывают о деньгах. В итоге эти зелёные циферки просто жрут гигантское количество бабла, не выполняя никакой конкретной задачи. 

Почему? Всё просто: автоматическое тестирование это просто дополнительный инструмент в системе минимизации рисков. А что нужно для того чтоб минимизировать риски? Правильно — иметь внятную и реалистичную модель этих самых рисков.

Вторая вещь в которой стоит себе признаться — у вас нет модели рисков. С вероятностью примерно 99% вы о ней даже никогда не думали. А значит все эти ваши тесты — пустая трата денег. 

И завершающая, третья вещь — модель рисков должна быть интегрирована в процесс разработки продукта сразу после бизнес-задачи. Так как по сути ваша модель рисков должна формировать этот самый процесс. От плохого кода должны защищать всяческие анализаторы/линтеры, от некачественной/неэффективной реализации логики должны защищать code review и нормально сформулированные требования. От проблем с производительностью — тесты производительности. Идеально — роботы уже должны научиться ломать всё подряд, без участия человека.

Вы разрабатывает конечный продукт, которым пользуются только конечные потребители через окно браузера? Ваш риск — пользователь не сможет выполнять критические для бизнес-задачи действия: положить товар в корзину, отправить отчёт в налоговую или оплатить подписку. Юнит тестирование в данном случае несёт в себе примерно никакого смысла, так как от того как у вас там внутри крутятся шестерёнки ничего совершенно не меняет. Пользователю плевать сколько у вас аргументов получает метод: три или пять. Его волнует только тот факт, что при нажатии на кнопку он получит результат.

Вы разрабатывает платформу, с которой кто-то интегрируется через HTTP? Ваш риск — интегратор не сможет выполнить критические для бизнес-задачи действия: создать новый виртуальный сервер, отменить отправку посылки или закрыть вентиль своего газгольдера. Юнит тестирование в данном случае тоже несёт в себе количество смысла близкое к нулю. Если по POST /valves/5794/close вентиль не закрывается, какая разница что не работает внутри? 

Вы разрабатывает платформу, с которой кто-то интегрируется через ваши программные API? Ваш риск — разработчик не сможет выполнить критические для бизнес-задачи действия: положить SMS сообщение в очередь или переключить электроснабжение с одной подстанции на другую. В этом случае вам нужно тестировать свои публичные интерфейсы, а не приватные. Никого не волнует что внутри SuperSCADA.current.failover_to(:backup) пошло не так и почему current вернул nil: из-за того что вызов произошел в другом треде или из-за того, что кто-то забыл вызвать super в method_missing.

Очень освежающий эффект о стоимости тестов даёт простая статистика: количество изменений в ваших тестах против количества изменений в продукте в вашей VCS. 

Так что моя позиция очень простая: юнит тестирование в примерно 99% случаев зло, по степени вреда сопоставимое с TDD (это вообще отдельная боль: как можно тестировать то, чего ещё нет?). 

Если правильно оценить свои риски и писать интеграционные тесты, самих тестов будет меньше, они будут лучше отражать ваши бизнес-задачи, их будет гораздо проще поддерживать. А у разработчиков появится дополнительное время, которое они могут потратить на что-то действительно полезное для бизнеса.

Возвращаясь к стабам/мокам: текущий ужас который идёт из коробки с рельсой вполне понятен эволюционно. Руби эта такая штука, в которой ни в чём нельзя быть уверенным. И вроде как лет 10 назад юнит тесты казались хорошей идей: давайте ассертами задолбим всё что можно, чтоб не дать закопать свинью. Но за эти 10 лет инструменты для тестирования шагнули очень далеко вперёд и сегодня это всё выглядит несколько странно. Например rspec-rails генерирует мне тесты для роутов. Для роутов, Карл! Зачем, если в соседнем тесте у меня уже есть тест который делает GET запрос в тот-же урл? 

Очень надеюсь что это всё ещё по инерции и скоро мы увидим переход к гораздо более эффективному подходу к управлению рисками, а не тупое долбление в методы.

А.

Max Lapshin

unread,
Aug 18, 2015, 3:27:15 PM8/18/15
to RubyOnRails to russian
Вот как-то так, да.  Хороший, эмоциональный и наполненный комментарий, спасибо.


Выжимка из него с моей колокольни: от HTTP приложения самое важное — правильное изменение наблюдаемого состояния и нереально круто то, что это всё можно свести к HTTP запросам (и немножко прочей фигне типа почты).

Поэтому для меня важнее всего проверить выполнение бизнес-функций, подергав за HTTP.

Юнит-тесты имеют смысл как средство борьбы с комбинаторной сложностью входных/выходных параметров, но никак не замена HTTP.

Хороший пример: в рельсах по умолчанию отключен рендеринг view в тестах. Это сделано из-за того, что для рельс нормально потратить 600-800 мс на рендеринг одного шаблончика. Там, где другие укладываются в 1-2 мс, а на 3 мс срабатывает аларм у админов, тут 800 мс. Но я знаю на 100%, что если в зеленом CI включить render_views, то полезут ошибки, которые и на продакшне случаются, или случатся завтра.  Но по умолчанию до сих пор они выключены.


Вот это и вызывает у меня вопрос и расстройство. Я сейчас буду писать к рельсам обертку для удобного тестирования их по HTTP, т.е. основной функции, потому что ничего подходящего я не нашел.




Victor Shepelev

unread,
Aug 18, 2015, 3:27:52 PM8/18/15
to ror...@googlegroups.com
...Начал писать длинный ответ, который начинался со слов «какая дичь», а также должен был использовать слово sustainability, но передумал.

Но на самом деле, у меня есть теория, что риальне хорошие разработчики — они как писатели, во многом. А пишут все, вообще говоря, по-разному. И все «паттерны» и «методологии» — по большому счёту, не утверждают «как надо», а позволяют назвать словами «как мне кажется правильным».

Вот вы офигеваете от концепции TDD со словами «как можно тестировать то, чего ещё нету», а я офигеваю от того, как можно в принципе эффективно разрабатывать без TDD. (И от утверждения что юнит-тесты — это «зло, по степени вреда сопоставимое» с чем-нибудь очень плохим.)

Какой вывод из этого можно сделать? Ну, можно решить что один из нас — Очень Плохой Разработчик (особенно учитывая, что мы друг друга не знаем). Можно попытаться «выяснить правду», и четыре года метать друг в друга аргументы, как делают на RSDN.ru в вечных тредах «статика против динамики», «виндовз против линукса», «айфон против андроида» вотэва.

А можно, мне кажется — да и наиболее осмысленно — пронаблюдать как и почему вашему темпераменту, стилю и «жанру» соответствует то, а моему, например — это.

Лично для меня — (disclaimer: я не пишу на рельсах ва-ап-ще, т.е. большая часть ваших проблем и инструментов мне чужие) — юнит-тесты в разы уменьшают скорость внесения изменений и, соответственно, увеличивают устойчивость разработки. НО. Юнит-тесты (и TDD в ещё большей степени) — это заодно и определённый майндсет («стиль» или «жанр», если возвращаться к писательской метафоре): если вам в нём нравится работать, то вы понимаете зачем они нужны. Но тогда и система ваша устроена как набор небольших атомарных юнитов, фрактально уходящих вдаль. Если это «не ваше» — то конечно юнит-тесты отягощение, а TDD и вовсе чушь.

Как-то так что ли.

18 августа 2015 г., 20:18 пользователь Alexey Bondar <alexey...@gmail.com> написал:

--
--
Данное сообщение отправлено Вам, так как Вы являетесь подписчиком группы "RubyOnRails to russian" на https://groups.google.com/group/ror2ru
FAQ группы находится по адресу: http://ru.wikibooks.org/wiki/RubyFAQ
 
Для того, чтобы отправить сообщение в эту группу, пошлите его по адресу
ror...@googlegroups.com
---
Вы получили это сообщение, поскольку подписаны на группу "RubyOnRails to russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес ror2ru+un...@googlegroups.com.
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/ror2ru/DBB8984C-1F18-4401-9114-A8FD1CD3BCCD%40gmail.com.

Антон Дьячук

unread,
Aug 21, 2015, 6:07:02 AM8/21/15
to ror...@googlegroups.com
Если
 * мы следуем принципу индивидуально отвественности
 * модуль А отвечает за хттп
 * мы знаем все что можем спросить у модуля и все что модуль нам может вернуть
послу тестирования модуля, обращения к модулю можно мотать

Другой вопрос в том, что, во первых, тесты могут быть написаны так чтобы они были зелеными, во вторых, я не нашел материалов по теории постановки научного эксперимента, а мозг как известно стремится чтобы все тесты были зелеными.

18 авг. 2015 г., в 13:59, Max Lapshin <max.l...@gmail.com> написал(а):

--
--
Данное сообщение отправлено Вам, так как Вы являетесь подписчиком группы "RubyOnRails to russian" на https://groups.google.com/group/ror2ru
FAQ группы находится по адресу: http://ru.wikibooks.org/wiki/RubyFAQ
 
Для того, чтобы отправить сообщение в эту группу, пошлите его по адресу
ror...@googlegroups.com
---
Вы получили это сообщение, поскольку подписаны на группу "RubyOnRails to russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес ror2ru+un...@googlegroups.com.
Чтобы посмотреть обсуждение на веб-странице, перейдите по ссылке https://groups.google.com/d/msgid/ror2ru/CAMxVRxAwwCYwALbGHA36%2BxO0Upp_bFkG0zB%3DUxf2xc9gUBuzOQ%40mail.gmail.com.

Phil Pirozhkov (pirj)

unread,
Aug 22, 2015, 1:41:05 AM8/22/15
to RubyOnRails to russian
Макс, знаю примерно специфику твоего приложения могу себе такое представть, но всё равно несколько блеклых пятен, не можешь прояснить?
 
Да, я бы сделал http-сервер иммитирующий фейсбук, потому что это задача аналогичная по сложности обвешиванию стабами запросы к фейсбуку.
Для Амазона мы такой сервер сделали за час и он помог вычистить кучу багов, когда переходили с моков на такой подход.
Вот, например, тестируешь ты своё приложение на корректность работы с внешним платёжным гейтом. Ты  пишешь свой платёжный гейт, который всегда возвращает "оплата произведена" для всех твоих пользователей? Или он рандомно возвращает все возможные варианты ответов? Как ты отслеживаешь, что твой код нормально работает со всеми вариантами ответов гейта? Есть ещё какой-то канал связи с этим эмулятором гейта, по которому ты говоришь "я сейчас тебя попрошу у Пирожкова списать 300р, а ты мне скажи, что их у него нет", или каждый раз поднимаешь этот сервер на отдельном порту/локальном домене с нужными параметрами?
 
Для рельс такая производительность недостижима? Или просто не получается запускать тесты параллельно?
Совсем недавно где-то проскальзывала статья про запуск тестов распределённо с помощью DRb. Не помню про rspec, но minitest умеет гонять тесты в параллель на все ядра.
Это собственно и причина необходимости атомарных тестов - если ты будешь стучаться к реальной базе данных, и будешь в параллель гонять тесты "регистрация нового пользователя" и "удаление старых пользователей", то тест "пользователей в таблице стало на 1 больше" будет периодически фейлить.
С этим и связан вопрос, как у тебя тестируются данные, общие для всех пользователей? Или это за гранью специфики, и такого у тебя просто нет?
Если пример с таблицей пользователей был неудачен, то вот тебе другой: "игрок создал новую игровую комнату, ей присвоен номер и она есть в списке игровых комнат". Или тест на удаление пользователей проходит полный путь по "создание-переход в статус платников-блокировка-разблокировка-удаление" чтобы проверить что пользователи у которых была оплата и которых блокировали потом нормально удаляются?
Наводит на мысль о том что можно форкать процесс в какой-то момент чтобы упростить проверку ветвлений тестов по комбинациям условий, о котором ты говорил. Увы только, что это не для Эрланга мысль.

А как у тебя тестируется админская часть в таком живом мире, где 100 других идущих тестов в параллель, например тест паджинации на странице списка пользователей.

А как проверяется наступление биллинг периода? Тоже внезапно один из тестов запускает такое событие? То есть время не линейно для всех тестов одновременно?

Max Lapshin

unread,
Aug 23, 2015, 3:05:34 PM8/23/15
to RubyOnRails to russian
Я напишу фейковый гейт, который юзеру А даст оплатить, юзеру Б не даст (и т.д.)


Как я уже писал: тесты именно в виде «пользователей стало на 1 больше» я не пишу. Я проверю, что создался именно этот пользователь, зачем тебе тестировать что их стало на 1 больше?


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

Александр Костриков

unread,
Aug 24, 2015, 4:46:10 AM8/24/15
to RubyOnRails to russian
>Если нужно протестировать, как наш софт ходит куда-то по HTTP, то поднимается HTTP сервер, в нём описываются нужные урлы и наш софт ходит к настоящему http серверу.
>Это очень правильный подход, потому что мы проверяем полностью весь стек.

Поддерживаю. 
Работа с ворохом моков в итоге гораздо сложнее работы с одним сервисом, эмулирующем API.
Это особенно явно проявляется в задачах где нужно "тестировать весь стэк", а не просто написать вывод блог-поста из БД.
В одном проекте пришёл к такому же выводу - проще написать один сервис, эмулирующий конечную платформу, чем пытаться поддерживать цельную систему из моков.
Дополнительный плюс - человек может всегда опереться на этот сервис, понять структуру внешней зависимости, "отдебажить" запрос, чего внешние системы, как правило не дают . А при моках - возникает отрывочное знание "оно ушло" и более ничего.
Естественно, минус - поддержка, незнание точной логики эмулируемой системы и так далее. Если проект однодневка, то проще моков накидать. Я уверен, на большом и сложном проекте подход эмуляции окупается.

P.S.
При этом если сервис быстрый, разрешает делать сколько угодно запросов, разрешает себя поставить локально, сбрасывать состояние/создавать tenant-ы и позволяет делать запросы на всём жизненном цикле процесса (нет где-то посередине бизнесс-логики Win приложения в котором *необходимо* что-то проставить) - то таким HTTP/что угодно сервером может быть и конечный сервис :)

Александр Костриков

unread,
Aug 24, 2015, 2:52:45 PM8/24/15
to RubyOnRails to russian
В одном предложении: "Ничто не гарантирует консистентность системы моков".

Houdini

unread,
Sep 29, 2015, 5:52:44 PM9/29/15
to RubyOnRails to russian
Макс, расскажи пожалуйста, как вы в эрливидео быстро поднимаете http сервер? Чем пользуетесь на эрланге?

Спасибо


On Tuesday, August 18, 2015 at 1:59:50 PM UTC+3, Max.L...@gmail.com wrote:

Max Lapshin

unread,
Sep 30, 2015, 3:02:35 AM9/30/15
to ror...@googlegroups.com
Мы используем cowboy, особых вариантов сегодня нет. Запускаем его хитровато
Reply all
Reply to author
Forward
0 new messages