Pull to refresh
23
0
Aleksandr Goida @ETman

Software Developer

Send message
При расчете будущих событий UTC не поможет, т.к. события, обычно, должны происходить в какое-то точное локальное время.
Скажем, как бы вы решали такую проблему наименьшими усилиями: надо расчитать даты запуска джоба в 10 утра по каждой из нескольких локаций, которые находятся в разных часовых поясах?
По моим расчетам, можно и через UTC: расчитываем последовательность, переводим в локальную, чтобы проверить 10 часов это или нет, сохраняем обратно в UTC.
А пожно просто забить как 10 утра локально и скедулер уже будет вызывать, без конвертаций и расчетов.

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

В своем примере я имел ввиду, что можно хранить только название таймзоны и date/time (локальный).
Да, относительно UTC вы правы. Я запутался.

На счет названия таймзоны. По моим расчетам она нужна именно, чтобы получить эти карты. Офсет в большинстве случаев не нужен, т.к. можно получать локальное из UTC + TimeZoneInfo. Но без офсета будет проблема с переводом в локальное время тех моментов, которые произошли в течение этого DST перехода. Как то так.
Есть несколько случаев, в которых UTC не поможет, даже если все четко с его сохранением и выводом.

1) Если вы сохраняете информацию о будущем событии, которое должно произойти именно в 10 утра в Апреле через год во Владивостоке. Сервера все в Лондоне. В течение года правительство решает не переходить на летнее время. В этом случае поможет сохранение в локальном времени.

2) При переходах от зимнего к летнему и обратно у вас может теряться или дублироваться час в UTC. В этом случае помогает наличие информации о смещении времени.

Вообще, чтобы описать конкретный момент во времени необходимо три величины: дата/время + оффсет + название тайм зоны. Если меньше информации, то время приблизительное, как ни крути. Но для бизнес задач может быть достаточным только UTC, бесспортно. Поэтому необходимо смотреть конкретный случай.
Просто по бытовому рассуждая: почему нельзя сказать, что ты это делать не хочешь. И ты готов обучить кого-то другого, чтобы ему передать эту эстафету?
Спасибо за интересные моменты и описание.

Не претендую ни на что, но мне описанные проблемы, кажутся, стандартными для ситуации, когда процесса обмена знаниями нет. Рассказать о чем-то, еще не обменяться знаниями, как вы сами подметили во втором пункте. А первый пункт связан с недальновидностью и не так важно чьей: менеджера или самого разраба. При повышении нагрузки, очевидным решением распределение задач между разрабами с обучение их до должного уровня. Принять решение об этом может менеджер, или сам разраб.
Если же ситуация иная: кто-то хочет чтобы ему дали эту задачу, а ему не дают, несмотря на пройденные курсы, то тут необходимо смотреть почему. Может быть никто не знает о новом специалисте, может нет доверия, может еще что. Об этом обобщенно сложно обсуждать.
Правильно ли я понимаю, что вы говорите о двух проблемах:
  1. о том, что докладчик становится, своего рода, «крайним» и все начнут его напрягать вместо того, чтобы сделать самим
  2. и то, что после пары лекций никто специалистом не станет.

Поясните, пожалуйста?
Посмотрите на это? https://github.com/rbeauchamp/Swashbuckle.OData
Сам только собираюсь глянуть.
Что конкретно имеется ввиду поясните, пожалуйста?
Я восхищаюсь вашим уровнем погружения в данную область. Очень интересные и ценные комментарии.

Вы правы и я с вами полностью согласен. Так будет правильнее, хотя писать тесты будет сложнее. Я даже уверен, что они станут менее поддерживаемыми, т.к. придется больше прописывать различных нюансов, как значения передаваемых типов. Мой тест не покажет проблему, если вдруг между маппером и следующим возовом DbCommands параметр приравнять NULL.

В данном случае, я оставляю эту часть проверки ручному тестированию. Думаю, программист в здравом уме не будет просто так вставлять NULL и не проверять данную модификацию никак. А закрыть все абсолютно дыры программно все равно не получится. Поэтому тут вопрос о балансе затрачиваемых ресурсов и результата, который дают тесты. Чрезмерно сильно проверять код там, где это не надо нет необходимости. У нас есть голова, чтобы знать и помнить о том, как он работает. А тест должен продокументировать основной ход выполнения, за счет его проверки, и проверить различные краевые случаи.

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

С идеалистической я бы сделал иначе.

Во-первых, стоит ответить на вопрос: зачем тестировать значения? Если это необходимо, то вероятно существует логика трансформации в тестируемом методе. Эту логику можно вытащить и тестировать отдельно. Т.о. используя данный компонет для трансформации (маппинга) вы будете уверены, что он выдает на выходе всегда правильный результат. Если нет, вы добавите еще один случай для проверки этого маппера.

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

Например, в случае, приведенном в статье, есть код с AutoMapper. Его было бы неплохо вытащить в отдельный компонент и покрыть его тестами. Не сам AutoMapper, а враппер, который внутри использует AutoMapper. И тогда я был бы уверен, что передав некое значение, я всегда в методах DbCommands получу ему соответствующее. Как-то так.

Но опять же. Я не хочу категорично выступать за такой подход, т.к. следует по конкретной задаче смотреть, имея в голове представление о работе тестируемого кода.
Очень позновательно о терминах. Спасибо. Про требования именно так.
На счет этого дам пояснения:
Потому что в чем основная ошибка (обоих) ваших тестов? Они не тестируют, что именно передано в метод

На мой взгляд именно так должен выглядеть самый первый тест на данную логику. По мере накопления багов или в ходе предпродакшн тестирования появятся тесты более специфияные. Но для работы данной логики такие детали, как передача конкретного значения может быть упущена. Это сделает тесты легкими и легко пишущимися/поддерживающимися. Спустя 3 месяца там 100% будет и тест на параметры и на какие-то значения, но зачем сразу?
Разница действительно незначительная. Она в том, что тест не знает о внутренней реализации тестируемого метода. Это важно для легкости тестов и понятности когда. Далее вы проверяете fake объектом не конкретную реализацию, а следствие (эффект) вызванный работой тестируемого метода.

Лично я и тот и другой использую подход и не вижу ничего критичного в замене одного другим. Второй случай мне кадется более показательным для описания логики метода.
Хочу уточнить правильно ли я Вас понял.
1) Вы утверждаете, что верифицируете сам факт вызова методов в купе со значениями передаваемых параметров.
2) Если кто-то создает классы, чтобы удобнее тестирвоать, то такой человек не понимает тестирование воообще.
Это то, что вы говорите?
Если в первом случае да, то мне интересно всегда ли Вы так пишете или только в некоторых случаях?
C extension-методами понятен подход. Но все же мне кажется сильно универсального тут не сделать. В итоге все равно получится ворох методов аля шоткатов для блоков кода. Типа инлайн функций в C++ (если память мне не изменяет). Поэтому, не совсем понимаю реальное преимущество, хотя согласен, что удобно так в некоторых случаях.

А что такое AST?

Да, кстати, этот IQueryProvider, по-сути, и есть DAO. Не так ли?
Если у вас extension-методы заточены под использование только с одним типом данных, то смысла в них столько же, сколько и в методах репозитория. В итоге получим одинаковое кол-во методов, только одни статик, а другие нет. Объясните еще раз разницу, пожалуйста, не уловил выше?

И второй момент: как в тестах замокать выборку не занимаясь настройкой данных? Например у вас проверяется алгоритм метода, который дергает такой вот .OnlyWithRecentOrders(), получая данные и что-то над ними делаеющий.
Вопрос иного характера, но мне интересно, как в случае с DB.Customers.Where(x => x.IsActive) можно замокать данную выборку в тестах, если не иметь метода в неком интерфейсе? Мне хотелось бы избежать настройки данных в тесте.
Для данного случая я сам вижу только выделение этого в метод интерфейса какого-то DAO.
Вы о том, чтобы одна реализация репозитория занималась получением данных из базы, а другая, например, кеширование? Т.е. в BLL дергается некий интерфейс, за которым на самом деле спрятана цепочка репозиториев, которые делают каждый свое. Об этом?

Information

Rating
Does not participate
Location
Lozenets, Sofiya, Болгария
Date of birth
Registered
Activity