У вас более широкий по возможностям хелпер. Но в целом опять же получается, что решение по сути очень похоже, код использования моего аккумулятора вообще практически идентичен вашему коду с демонстрацией базовых возможностей на главной странице. Это радует :).
Посмотрел, спасибо. Там, получается, используется в точности такой же подход, с передачей делегатов. Только переходить с NUnit на другой фреймворк уже будет слишком радикальным шагом. Но вообще здорово, что в таком фреймворке реализовали настолько похожее решение.
Забавно, насколько я понимаю, подход у вас получился похожий очень? Это интересно.
Почитал вашу статью, мы в подобных случаях для устранения эффекта разбитых окон такие тесты в CI-системе карантинили. В таком случае тест все еще выполняется, его результат логируется и доступен для просмотра, но падение теста в карантине не вызывает паденеия всего билда. Очень удобно получалось. Не знаю, есть ли у вас в системе подобная возможность. Мы используем Bamboo.
Про параметризированный тест для данного примера вы правы, действительно рациональнее и компактнее получается. Спасибо, перепишу в проекте место, по которому этот пример сделан :). Такие случаи, соответственно, отпадают из области использования класса.
А в целом, по поводу тестов на удаленной машине: их в любом случае нужно прогонять в окружении, где развернут проект, и их результат от локального может там отличаться из-за разных факторов вроде часовых поясов и прочих особенностей конкретного окружения. Поэтому анализировать результаты по текстовым сообщениям приходится в любом случае время от времени, а чем больше информации получается из них, тем лучше, лишний билд и запуск тестов может съесть кучу времени. То, что состояния у теста два — это так, но когда оно красное, то лучше, когда ошибки выведены все. На мой взгляд, это как с компиляцией, она тоже может быть или успешная, или нет, но нехорошо же, если вам при неуспешной ошибку вам выводят только одну, а остальные только при следующей.
А-а, вы дебаг теста имели ввиду. Неправильно вас понял в первый раз. Тогда да, вы правы, отладка возможно будет менее удобной. Но зато, опять же, если будет несколько ошибок, то увидите все сразу в конце, а не вторую лишь после исправления первой и ребилда. Это особенно важно, если по тем или иным причинам проект у вас целиком билдится и отлаживается не локально, а в CI системе, например.
Это не так, всегда ведь есть параметр message у любого метода Assert'a для вывода развернутого сообщения. Эти сообщения в итоговом выводе аккумулятора будут сохранены. Даже в топике, например, в тесте конструктора, каждое из падений будет ясно видно по сообщению об ошибке. В примере с логином я просто поленился писать сообщения, что вообще говоря нехорошо делать :).
В настоящем примере короткий код конструктора был покрыт в тесте десятком немного, но разных ассертов, семантически проверящих одно и то же. 10 методов для такого делать представлялось неудобным.
С описанного вами простого способа у меня как раз началась цепочка рассуждений, которая привела к решению описанному в посте, отдельный не статический класс. В SetUp кстати записывать мне показалось некрасивым, т.к. это нужно далеко не во всех тест-методах, но это и не суть.
Магический способ очень интересный. Как раз недавно использовали CallContext для управления Lifetime некоторых DAL-объектов, понравилось. Но здесь это пожалуй оверкилл и слишком комплексно, как вы и говорите.
А почему в целом от копивания интерфейса Assert я пришел к классу-аккумулятору:
1. Это все же отчасти содержит копирование;
2. Ну очень много методов там придется оборачивать, если основательно делать, а время не резиновое;
3. Самое неприятное: внутри каждого метода-обертки будет одинаковый абсолютно код вида try { Assert.Foo(args); } catch { /* запомнить */ }, что ужасно однообразно и громоздко на мой взгляд.
По поводу стандартного кода каждый раз: много ассертов в одном тесте все же не столь часто нужно, а когда нужно, то по-моему с описанным классом как раз получается декларативно и понятно, что делается, хоть читабельность внешнего кода возможно и страдает несколько из-за лямбд.
Модификация исходников NUnit мне представляется еще более костыльным решением. Прежде всего потому, что это ведь будет не нормальный reuse, а по сути copy-paste со всеми его вытекающими в виде убитой поддерживаемости и прочего: обновится NUnit, придется вручную обновлять свой код, чтобы оставаться up-to-date.
Кроме того, если допустить сколько-нибудь удобную и лаконичную возможность добиться подобного с помощью наследования, делегирования или экстеншенов, то использование для запоминания результатов сам Assert или его модификацию это тоже ничего хорошего. Assert статический и соответственно запоминать тогда тоже нужно будет в статике, что кошмарно. Черт знает что будет происходить при параллельном выполнении тестов и т.п.
По поводу кодогенерации вы и сами признали, что не вариант. Так и получается, что решения удобнее, чем такой класс-аккумулятор мне не видится. Был бы рад послушать еще идеи и советы.
И спасибо за фидбэк по поводу читаемости, взгляд со стороны это всегда полезно :)
Забавно, насколько я понимаю, подход у вас получился похожий очень? Это интересно.
Почитал вашу статью, мы в подобных случаях для устранения эффекта разбитых окон такие тесты в CI-системе карантинили. В таком случае тест все еще выполняется, его результат логируется и доступен для просмотра, но падение теста в карантине не вызывает паденеия всего билда. Очень удобно получалось. Не знаю, есть ли у вас в системе подобная возможность. Мы используем Bamboo.
А в целом, по поводу тестов на удаленной машине: их в любом случае нужно прогонять в окружении, где развернут проект, и их результат от локального может там отличаться из-за разных факторов вроде часовых поясов и прочих особенностей конкретного окружения. Поэтому анализировать результаты по текстовым сообщениям приходится в любом случае время от времени, а чем больше информации получается из них, тем лучше, лишний билд и запуск тестов может съесть кучу времени. То, что состояния у теста два — это так, но когда оно красное, то лучше, когда ошибки выведены все. На мой взгляд, это как с компиляцией, она тоже может быть или успешная, или нет, но нехорошо же, если вам при неуспешной ошибку вам выводят только одну, а остальные только при следующей.
Магический способ очень интересный. Как раз недавно использовали CallContext для управления Lifetime некоторых DAL-объектов, понравилось. Но здесь это пожалуй оверкилл и слишком комплексно, как вы и говорите.
А почему в целом от копивания интерфейса Assert я пришел к классу-аккумулятору:
1. Это все же отчасти содержит копирование;
2. Ну очень много методов там придется оборачивать, если основательно делать, а время не резиновое;
3. Самое неприятное: внутри каждого метода-обертки будет одинаковый абсолютно код вида
try { Assert.Foo(args); } catch { /* запомнить */ }, что ужасно однообразно и громоздко на мой взгляд.По поводу стандартного кода каждый раз: много ассертов в одном тесте все же не столь часто нужно, а когда нужно, то по-моему с описанным классом как раз получается декларативно и понятно, что делается, хоть читабельность внешнего кода возможно и страдает несколько из-за лямбд.
Кроме того, если допустить сколько-нибудь удобную и лаконичную возможность добиться подобного с помощью наследования, делегирования или экстеншенов, то использование для запоминания результатов сам Assert или его модификацию это тоже ничего хорошего. Assert статический и соответственно запоминать тогда тоже нужно будет в статике, что кошмарно. Черт знает что будет происходить при параллельном выполнении тестов и т.п.
По поводу кодогенерации вы и сами признали, что не вариант. Так и получается, что решения удобнее, чем такой класс-аккумулятор мне не видится. Был бы рад послушать еще идеи и советы.
И спасибо за фидбэк по поводу читаемости, взгляд со стороны это всегда полезно :)