Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 03.02.10 17:18
Оценка: 1 (1)
Здравствуйте,
Сегодня тесты выявили такой баг: при сохранении нового клиента, вместо того, чтобы ему выставить некоторую цену доставки груза по умолчанию, эта цена доставки груза выставлялась вообще всем клиентам. Грубо говоря код такой был:

...
if (customer.ID == 0)
{
    using (var transactionScope = new TransactionScope())
    {
        CustomerAccessor.Insert(customer);
        CustshipmentsAccessor.SetShipmentPricesForAllCustomers(...); // а надо было CustshipmentsAccessor.SetShipmentPricesForCustomer(...);

        transactionScope.Complete();
    }
}
...

Т.е. не ту функцию вызывал... К счастью в релиз это не успело уйти.

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

Но вопрос в том — как лучше тестировать чтобы такая ошибка обнаружилась. Ведь если для каждой функции писать кучу тестов и код, который проверяет как изменилось состояние БД (не затронулись ли другие строки и таблицы), то с ума можно сойти (я все-таки не маньяк-тестировщик, тесты в основном пишу только на наиболее критичные для бизнеса, либо сложные функции). Можно ли как-то проще?
Re: Как поймать тестами такой баг?
От: XopoSHiy Россия http://cleancodegame.github.io/
Дата: 03.02.10 17:33
Оценка: 9 (3) +4
Здравствуйте, MozgC, Вы писали:

MC>Но вопрос в том — как лучше тестировать чтобы такая ошибка обнаружилась.


Неправильный вопрос.
Правильный такой: Что нужно сделать, чтобы обезопасить себя от таких ошибок.
Тесты — это только один из способов — оборона. Наверное, оборону можно как-то тоже прокачать, но я бы в данной ситуации не сидел в обороне, а наносил бы упреждающие удары. А именно я бы перестал давать методам имена вида ЧтоТоОченьОченьОченьДлинное и ЧтоТоОченьОченьОченьДлинноеДляВсех, чтобы их было не так просто спутать.
---
http://twitter.com/xoposhiy
http://xoposhiy.moikrug.ru
Re[2]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 03.02.10 17:43
Оценка:
Здравствуйте, XopoSHiy, Вы писали:

XSH>А именно я бы перестал давать методам имена вида ЧтоТоОченьОченьОченьДлинное и ЧтоТоОченьОченьОченьДлинноеДляВсех, чтобы их было не так просто спутать.


А предложите для примера свой вариант названия этих двух методов?
Re: Как поймать тестами такой баг?
От: rlabs Россия  
Дата: 03.02.10 18:07
Оценка: 7 (1)
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте,

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

Не уверен по поводу "проще", но в этой функциональности наверняка есть требование "У каждого клиента своя цена доставки", и проверяется, допустим, следующими тестами:

public void СтарыеЦеныСохраняютсяПриДобавленииНовогоКлиента() {
...
client1.add( price1 )
client2.add( price2 )
assertEquals( price1, client1.getPrice() )
}

public void НовыйКлиентМожетВыставитьСвоюЦену() {
...
client3.add( price3 )
client4.add( price4 )
assertEquals( price4, client4.getPrice() )
}


Ничего особо маньячного в этом не вижу, сценарии как сценарии. Полностью защититься от ситуации "а вот на это теста у нас не было" нельзя в принципе. Всегда будут находиться новые ситуации (хотя данный конкретный случай достаточно простой).
Alex Nikulin
Yota Lab
Re: Как поймать тестами такой баг?
От: fk0 Россия https://fk0.name
Дата: 03.02.10 18:27
Оценка:
Здравствуйте, MozgC, Вы писали:


MC> CustshipmentsAccessor.SetShipmentPricesForAllCustomers(...); // а надо было CustshipmentsAccessor.SetShipmentPricesForCustomer(...);


MC>Но вопрос в том — как лучше тестировать чтобы такая ошибка обнаружилась. Ведь если для каждой функции писать


Затрудняюсь сказать как тестировать, но знаю как сделать, чтоб такого вообще не появлялось:

НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.
И не должно быть похожих имён функций, на буковку различающихся. Сильно помогает -- проверено электроникой.
Re[2]: Как поймать тестами такой баг?
От: Аноним  
Дата: 03.02.10 18:46
Оценка: 17 (2) +2
Здравствуйте, fk0, Вы писали:

fk0> НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.

fk0>И не должно быть похожих имён функций, на буковку различающихся. Сильно помогает -- проверено электроникой.
я бы тоже дал такое же имя, можете пример нормального, для данного случая, имени привести?
Re: Как поймать тестами такой баг?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.02.10 19:58
Оценка: 7 (1)
Здравствуйте, MozgC, Вы писали:

MC>Но вопрос в том — как лучше тестировать чтобы такая ошибка обнаружилась. Ведь если для каждой функции писать кучу тестов и код, который проверяет как изменилось состояние БД (не затронулись ли другие строки и таблицы), то с ума можно сойти (я все-таки не маньяк-тестировщик, тесты в основном пишу только на наиболее критичные для бизнеса, либо сложные функции). Можно ли как-то проще?


В общем случае тестировать то что код не сделал чего-то лишнего (кроме того что сделал то что нужно) слишком накладно.

Но если говорить о коде, работающем с БД, то проверять нужно не в той формулировке, которую я выделил в цитате, а в немного другой: правильно ли произошло изменение состояния БД.

Т.е. нам нужно иметь набор тестовых данных, причем шире чем данные, которые затрагиваются тестируемым кодом. Нужно иметь набор эталонных данных и умение сравнивать состояние БД с эталонными данными. Например, эталонные данные могут быть в формате plain text, тогда нужно уметь выгрузить состояние БД в plain text и сравнить с эталонным набором.

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


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

Или ты поднимаешь вопрос полезности неизолированных тестов?
Re[2]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 04.02.10 02:05
Оценка:
Здравствуйте, fk0, Вы писали:

fk0> НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.


Понимаете, в чем дело, щас не старинные экраны в которые по 60 символов влезает, а широкоформатные мониторы, к тому же современные IDE избавляют от необходимости полностью имена классов и методов печатать. Зато если я сам посмотрю на свой код через год — у меня не возникнет вопросов "а что делает этот метод?" — это ясно из названия. То же самое если в проект придет новый человек — ему будет проще понять что делает конкретный класс или метод просто по одному названию.
Re[2]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 04.02.10 02:13
Оценка:
Здравствуйте, samius, Вы писали:

S>Или ты поднимаешь вопрос полезности неизолированных тестов?

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

В общем пока я сделал пару выводов:
1) Действительно меня подвело имя метода. В изначальном посте я просто по памяти напечатал пример. На самом деле метод назывался CustshipmentsAccessor.UpdateShipmentPrices(int countryID, ...). Если бы имя метода включало упоминание о стране (т.е. что цены выставляются для всех клиентов из страны), то ошибиться было бы сложнее.
2) Такие ситуации протестировать можно, и в принципе несложно (пример привел rlabs), но все-таки это добавит лишних трудозатрат, и при этом все равно не гарантирует того что метод не умудрится изменить чего-то чего не должен Гарантировать можно, только если делать в каждом методе полное сравнение получившегося состояния базы данных с эталонным состоянием, но че-то по-моему это будет геморойный подход (сходу даже не знаю как такое простым способом реализовать для большой базы) и такие тесты будут долго выполняться.
Re[3]: Как поймать тестами такой баг?
От: Twirl Швеция  
Дата: 04.02.10 03:34
Оценка: 8 (2)
Хочу добавить, что частично, отливаливать такие баги так же помогает код ревью.
Re[3]: Как поймать тестами такой баг?
От: Other Sam Россия  
Дата: 04.02.10 05:45
Оценка:
// Вариант 1 (ООП структурирование системы)
// Есть custService через который можно управлять клиентами
// и только через него.
// У сервиса есть DefaultPriceSet (для клиентов, там все
// ценники по умолчанию для клиентов)
// Метод создающий новый объект Customer требует параметр PriceSet
PriceSet prs = custService.getDefaultPriceSet().clone();
prs.ShipmentPrice = 5.22;
Customer customer = custService.newCustomer(prs);


Вариант 2 (Проверка суперсостояния)
Для БД пишется один метод который проверяет суперсостояние.
Целостность данных в БД трудно проверить полностью констраинтами самой
БД. Поэтому все такие моменты прописываем в отдельный код, который можем
вызывать перед и после тестов.
Однако у такого подхода низнкая применимость. Писать такой тест может
архитектор или ведущий проктировщик, а в таком случае развивать эту
часть кода рядовые программисты либо не могут (нехватает целостного
видения системы), либо не хотят (стремаются лезть в работу вышестоящего).
Т.е. такой подход могут применять небольшие команды 2-4 человека,
исповедующие XP, или хотябы использующие парное программирование и TDD.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Как поймать тестами такой баг?
От: fk0 Россия https://fk0.name
Дата: 04.02.10 08:16
Оценка: 1 (1)
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, fk0, Вы писали:


fk0>> НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.


MC>Понимаете, в чем дело, щас не старинные экраны в которые по 60 символов влезает, а широкоформатные мониторы, к тому же


А глаза всё те же, что и в 80-х, как и впрочем мозги. Да и в 80-х в текстовом режиме 132 символа в строке поддерживалось.

fk0>> современные IDE избавляют от необходимости полностью имена классов и методов печатать. Зато если я сам посмотрю на свой код через год — у меня не возникнет вопросов "а что делает этот метод?" — это ясно из названия.


Автодополнение нужно, в основном, где имена функций шириной в пол-экрана -- да... Набрать уж что-нибудь на клавиатуре, при
многолетней тренировке обычно затруднений не вызывает. Что делает метод из названия нифига не ясно. Могут быть многочисленные ньюансы. И что в действительности позволяют современные IDE -- это хотя бы перейти к определению метода и почитать там трёхстрочный комментарий, что он делает в действительности. Не, я конечно тоже против 6-буквенных имён, но есть две крайности...
Re[3]: Как поймать тестами такой баг?
От: bl-blx Россия http://yegodm.blogspot.com
Дата: 04.02.10 08:47
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>2) Такие ситуации протестировать можно, и в принципе несложно (пример привел rlabs), но все-таки это добавит лишних трудозатрат, и при этом все равно не гарантирует того что метод не умудрится изменить чего-то чего не должен Гарантировать можно, только если делать в каждом методе полное сравнение получившегося состояния базы данных с эталонным состоянием, но че-то по-моему это будет геморойный подход (сходу даже не знаю как такое простым способом реализовать для большой базы) и такие тесты будут долго выполняться.


Такого можно добиться, если каждый Accessor абстрактен настолько, что взамен
реальной базы позволяет виртуальную (in-memory db) использовать. Тогда удаётся
большее число инвариантов проверять за приемлимое время. Да и воссоздать
эталонное состояние внутри теста становится более-менее простым делом.

Кстати, для справки, еще пара примеров, где упрощенный юнит-тест может
обмануть:
1) Самодельные имплементации коллекций. На скорую руку обычно проверяют, что
после add()/remove() элемент присутствует/отсутствует в коллекции и всё.
Правильный подход — как минимум, дополнительно убедиться, что количество
элементов изменилось надлежащим образом и все остальные элементы по-прежнему
в коллекции.
2) Реальный случай с fall-through в switch-конструкции, что в джаве, к сожалению,
допустимо. Информация в торговой системе о трейде приходила с нескольких внешних
систем и switch-case решал с какой комбинацией параметров сохранять этот трейд для
каждого из источников (штук пять кейсов было). В один прекрасный момент случайно
потеряли break — получили по две записи на каждый трейд в базе для одной из систем.
Нашли случайно, когда пользователи возбудились из-за неверной агрегатной суммы по
всем трейдам.

И, да, код-ревью резко снижает вероятность подобных дефектов.
El pueblo unido jamás será vencido.
Re[4]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 04.02.10 13:20
Оценка:
Здравствуйте, fk0, Вы писали:

fk0>Не, я конечно тоже против 6-буквенных имён, но есть две крайности...


Т.е. по вашему SetCustomerShipmentPrices() — это крайность?
Re[3]: Как поймать тестами такой баг?
От: rlabs Россия  
Дата: 04.02.10 19:56
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Понимаете, в чем дело, щас не старинные экраны в которые по 60 символов влезает, а широкоформатные мониторы, к тому же современные IDE избавляют от необходимости полностью имена классов и методов печатать. Зато если я сам посмотрю на свой код через год — у меня не возникнет вопросов "а что делает этот метод?" — это ясно из названия. То же самое если в проект придет новый человек — ему будет проще понять что делает конкретный класс или метод просто по одному названию.


Даже с большими мониторами, удобнее работать с короткими и лаконичными названиями методов. Об этом и дядя Боб писал, по-моему. Суть скорее не в длине названия, а в его логичности и не спутываемости: если названия отличаются только непного, и это отличие не бросается в глаза, повышается риск ошибки.

Я сам видел код с методами типа ПоискатьЗначениеПоТаблицеИДобавитьЕслиЕгоЕщеНет(), и поддерживать его — совсем не здорово. Другой пример — методы с булевыми параметрами: когда смотришь только на вызов, не всегда ясно отличие между CreateReport( true ) и CreateReport( false ).
Alex Nikulin
Yota Lab
Re[3]: Как поймать тестами такой баг?
От: rlabs Россия  
Дата: 04.02.10 20:04
Оценка: 1 (1)
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, samius, Вы писали:


MC>2) Такие ситуации протестировать можно, и в принципе несложно (пример привел rlabs), но все-таки это добавит лишних трудозатрат, и при этом все равно не гарантирует того что метод не умудрится изменить чего-то чего не должен :( Гарантировать можно, только если делать в каждом методе полное сравнение получившегося состояния базы данных с эталонным состоянием, но че-то по-моему это будет геморойный подход (сходу даже не знаю как такое простым способом реализовать для большой базы) и такие тесты будут долго выполняться.


Можно пойти от обратного. Если есть возможность подменить БД стабом(а без этого как-то странно проводить модульное тестирование), можно отслеживать _затронутые_ вызовом метода объекты БД, и проверять, что других вызовов не было. То есть, какбы, считаем, что метод обновления цен может трогать только таблицы Price и Customer, и если был вызов update любой другой (не важно какой) — тест валится. Хотя, так себе подход.
Alex Nikulin
Yota Lab
Re[3]: Как поймать тестами такой баг?
От: XopoSHiy Россия http://cleancodegame.github.io/
Дата: 25.02.10 18:25
Оценка: 1 (1)
Здравствуйте, MozgC, Вы писали:

MC>А предложите для примера свой вариант названия этих двух методов?


Что-то я забыл про этот топик
Впрочем можете считать, что я все это время думал над названием

MC> CustshipmentsAccessor.SetShipmentPricesForAllCustomers


Вот такой вариант сделает ошибку невозможной:
CustshipmentsAccessor.SetPrice.ForAll(...)
CustshipmentsAccessor.SetPrice.For(customer, ...)


Просто потому что после второй точки придется явно выбрать ForAll или не фор олл.
А вообще, конечно, все зависит от того, что там ещё в этом CustshipmentAccessor живет. Может быть есть варианты и более натуральные.
---
http://twitter.com/xoposhiy
http://xoposhiy.moikrug.ru
Re[4]: Как поймать тестами такой баг?
От: Gmoorick Россия  
Дата: 01.03.10 15:00
Оценка: 8 (1)
Здравствуйте, rlabs, Вы писали:

R>Здравствуйте, MozgC, Вы писали:


MC>>Здравствуйте, samius, Вы писали:


MC>>2) Такие ситуации протестировать можно, и в принципе несложно (пример привел rlabs), но все-таки это добавит лишних трудозатрат, и при этом все равно не гарантирует того что метод не умудрится изменить чего-то чего не должен Гарантировать можно, только если делать в каждом методе полное сравнение получившегося состояния базы данных с эталонным состоянием, но че-то по-моему это будет геморойный подход (сходу даже не знаю как такое простым способом реализовать для большой базы) и такие тесты будут долго выполняться.


R>Можно пойти от обратного. Если есть возможность подменить БД стабом(а без этого как-то странно проводить модульное тестирование), можно отслеживать _затронутые_ вызовом метода объекты БД, и проверять, что других вызовов не было. То есть, какбы, считаем, что метод обновления цен может трогать только таблицы Price и Customer, и если был вызов update любой другой (не важно какой) — тест валится. Хотя, так себе подход.


А я бы еще добавил, что юнит тестирование, почти всегда не совместимо с проверкой чего-то, что не написано вами (вашей командой).
В данном случае, тестировать надо то, что был вызван именно тот метод, который предполагалось использовать.

Проверка того, как изменились данные в базе при вызове метода — это уже задача интеграционных тестов.

Если брать пример топик стартера, то тут тест был бы примерно таким:

myObject.Update();
Mock.VerifyWasCalled(()=>MockedCustshipmentsAccessor.SetShipmentPricesForCustomer(...));

Если писать в режиме TDD, то чтобы допустить такой баг, нужно ошибиться и в тесте и в коде одновременно.

Все что остается, это проверить (уже в наборе интеграционных тестов), что SetShipmentPricesForAllCustomers действительно обновляет все записи, а SetShipmentPricesForCustomer только для конкретного покупателя.
Ну и потом провести рефакторинг, чтобы не путать имена.
Re[5]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 01.03.10 15:12
Оценка:
Здравствуйте, Gmoorick, Вы писали:

G>В данном случае, тестировать надо то, что был вызван именно тот метод, который предполагалось использовать.


Я боюсь, что если писать тест после кода, то так же просто возьмешь и в тесте тоже выберешь не тот метод (потому что перед этим сначала поглядишь на тестируемый метод и увидишь там ...FoAllCustomers() — и поэтому автоматом напишешь Mock.VerifyWasCalled(()=>MockedCustshipmentsAccessor.SetShipmentPricesForAllCustomers(...));

Но наверное это уже переходит в разряд, что если мозг не напрягать, то что угодно можно сломать.
Re[6]: Как поймать тестами такой баг?
От: Gmoorick Россия  
Дата: 01.03.10 15:20
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, Gmoorick, Вы писали:


G>>В данном случае, тестировать надо то, что был вызван именно тот метод, который предполагалось использовать.


MC>Я боюсь, что если писать тест после кода, то так же просто возьмешь и в тесте тоже выберешь не тот метод (потому что перед этим сначала поглядишь на тестируемый метод и увидишь там ...FoAllCustomers() — и поэтому автоматом напишешь Mock.VerifyWasCalled(()=>MockedCustshipmentsAccessor.SetShipmentPricesForAllCustomers(...));


MC>Но наверное это уже переходит в разряд, что если мозг не напрягать, то что угодно можно сломать.

именно поэтому я написал про TDD, юнит-тест после кода (если это не дебаггинг)- это имхо время на ветер.
Re: Как поймать тестами такой баг?
От: TarasCo  
Дата: 01.03.10 19:21
Оценка:
Чисто в теории, наверное надо использовать mock объекты, в частности для CustshipmentsAccessor. А дальше писать тест-кейс, в котором изобразить что-то вроде:

EXPECT_CALL( SetShipmentPricesForCustomer )

Но это в теории все прекрасно, а как написать нормальные тесты с mock объектами — я не знаю. Хотя опять же в теории тест-кейсы с мок-объекатми должны также прекрасно документировать код. Типа посмотрел на кейс и сразу виден весь алгоритм. Но это видимо сродни искусству....
Да пребудет с тобою сила
Re: Как поймать тестами такой баг?
От: Aikin Беларусь kavaleu.ru
Дата: 27.05.10 15:28
Оценка:
Здравствуйте, MozgC, Вы писали:

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

Что же можно сделать чтобы уберечь себя от подобных ошибок? ИМХО, проектировать удобный "error free" интерфейс.

У меня есть 3 предложения по улучшению этого интерфейса:
1) ForAllCustomers и ForCustomer вынести в начало названия.
Получим ForAllCustomersSetShipmentPrices и ForCustomerSetShipmentPrices. Ошибиться стало намного сложнее.
Для пущего удобства чтения можно добваить подчеркивание: ForAllCustomers_SetShipmentPrices и ForCustomer_SetShipmentPrices (и шлите в лес всех кто говорит, что подчеркивчания "некошерны". ИМХО, кошерно все что удобно. Тут подчеркивание удобно).
Как бонус получаем разделение методов на две группы в автодополнении. (это, кстати, наведет вас на мысль, что класс играет две роли: работа с одним кастомером и со всем кастомерам, а оттуда недалеко до двух классов)


Не совсем понимаю как получается, что SetShipmentPricesForCustomer не получает параметром конкретного кастомера. Возможно, он передается из CustomerAccessor через какой-то контекст.
2) Можно передавать кастомера параметром в метод. Тогда SetShipmentPricesForAllCustomers банально не скомпилируется.
3) Можно проверять наличие кастомера в контексте из SetShipmentPricesForAllCustomers. И если он там есть выкидывать исключение (с пояснением что как и почему).


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


СУВ, Aikin
... << RSDN@Home 1.2.0 alpha 4 rev. 1466>>
Re[2]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 27.05.10 16:36
Оценка:
Здравствуйте, Aikin, Вы писали:

A>1) ForAllCustomers и ForCustomer вынести в начало названия.

Я уже типа того и сделал, только еще больше переименовал

A>Не совсем понимаю как получается, что SetShipmentPricesForCustomer не получает параметром конкретного кастомера. Возможно, он передается из CustomerAccessor через какой-то контекст.

A>2) Можно передавать кастомера параметром в метод. Тогда SetShipmentPricesForAllCustomers банально не скомпилируется.
Одна функция принимает первым параметром int customerID, а другая int countryID =) Поэтому так и вышло
Re[3]: Как поймать тестами такой баг?
От: Аноним  
Дата: 27.05.10 16:57
Оценка:
Здравствуйте, MozgC, Вы писали:

A>>2) Можно передавать кастомера параметром в метод. Тогда SetShipmentPricesForAllCustomers банально не скомпилируется.

MC>Одна функция принимает первым параметром int customerID, а другая int countryID =) Поэтому так и вышло
Недавно, кстати, AndrewK писал о типизированных Id.
Т.е. вместо int CountryId пишем Key<Country>, мне понравилось, начал использовать у себя
Re[3]: Как поймать тестами такой баг?
От: Aikin Беларусь kavaleu.ru
Дата: 27.05.10 17:33
Оценка:
Здравствуйте, MozgC, Вы писали:

A>>Не совсем понимаю как получается, что SetShipmentPricesForCustomer не получает параметром конкретного кастомера. Возможно, он передается из CustomerAccessor через какой-то контекст.

A>>2) Можно передавать кастомера параметром в метод. Тогда SetShipmentPricesForAllCustomers банально не скомпилируется.
MC>Одна функция принимает первым параметром int customerID, а другая int countryID =) Поэтому так и вышло
Теперь понятно. Опять проблема интерфейса.
Надо узнать что же предлагал AndrewK, а то у меня кроме экстеншен метода для int (id.of<Customer>()) и new Customer(id) ничего в голову не приходит.

СУВ, Aikin
... << RSDN@Home 1.2.0 alpha 4 rev. 1466>>
Re[4]: Как поймать тестами такой баг?
От: Aikin Беларусь kavaleu.ru
Дата: 27.05.10 17:33
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Недавно, кстати, AndrewK писал о типизированных Id.

А>Т.е. вместо int CountryId пишем Key<Country>, мне понравилось, начал использовать у себя
А можно пример? А еще лучше ссылку?

СУВ, Aikin
... << RSDN@Home 1.2.0 alpha 4 rev. 1466>>
Re[5]: Как поймать тестами такой баг?
От: MozgC США http://nightcoder.livejournal.com
Дата: 27.05.10 17:50
Оценка:
Здравствуйте, Aikin, Вы писали:

А>>Недавно, кстати, AndrewK писал о типизированных Id.

А>>Т.е. вместо int CountryId пишем Key<Country>, мне понравилось, начал использовать у себя
A>А можно пример? А еще лучше ссылку?

Трактат о ключевых полях
Автор: IT
Дата: 09.02.10
Re[6]: Как поймать тестами такой баг?
От: Aikin Беларусь kavaleu.ru
Дата: 27.05.10 18:14
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Трактат о ключевых полях
Автор: IT
Дата: 09.02.10

Угу, об этом я знаю. Еще МакКоннел в совершенном коде писал. Вот только совсем не затронут более важный вопрос: как удобно создать этот ключ.
Мест где нужно передать ключ намного больше чем мест где ключ объявлен. Поэтому нужно думать о юзабилити создания ключа из int'а, а не о том как же удобно описать сам ключ.
Я до сих пор использовал new Customer(id) в случаях когда нужна типизация.

СУВ, Aikin
... << RSDN@Home 1.2.0 alpha 4 rev. 1466>>
Re[3]: Как поймать тестами такой баг?
От: Head Ache  
Дата: 30.09.10 03:36
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, fk0, Вы писали:


fk0>> НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.


MC>Понимаете, в чем дело, щас не старинные экраны в которые по 60 символов влезает, а широкоформатные мониторы, к тому же современные IDE избавляют от необходимости полностью имена классов и методов печатать. Зато если я сам посмотрю на свой код через год — у меня не возникнет вопросов "а что делает этот метод?" — это ясно из названия. То же самое если в проект придет новый человек — ему будет проще понять что делает конкретный класс или метод просто по одному названию.


В чем проблема-то?

Customer.SetPrice
AllCustomers.SetPrice
Этот аккаунт покинут.
Re[3]: Как поймать тестами такой баг?
От: Аноним  
Дата: 30.09.10 06:23
Оценка: +1
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, fk0, Вы писали:


fk0>> НАДО ДАВАТЬ ФУНКЦИЯМ НОРМАЛЬНЫЕ ИМЕНА. ЧИИИИТААААЕЕЕМЫЫЫЫЕЕЕЕЕ! А не блаблабла в пол-экрана шириной.


MC>Понимаете, в чем дело, щас не старинные экраны в которые по 60 символов влезает, а широкоформатные мониторы, к тому же современные IDE избавляют от необходимости полностью имена классов и методов печатать. Зато если я сам посмотрю на свой код через год — у меня не возникнет вопросов "а что делает этот метод?" — это ясно из названия. То же самое если в проект придет новый человек — ему будет проще понять что делает конкретный класс или метод просто по одному названию.


И что, теперь моск тоже со скоростью видеокарты работает

От перепутывания и опечаток не спасут и короткие имена.
Попробуйте не перепутать i и j в каком-нибудь алгоритме сортировки.
Re[5]: Как поймать тестами такой баг?
От: Воронков Василий Россия  
Дата: 15.10.10 13:41
Оценка: 1 (1)
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, fk0, Вы писали:

fk0>>Не, я конечно тоже против 6-буквенных имён, но есть две крайности...
MC>Т.е. по вашему SetCustomerShipmentPrices() — это крайность?

А ты как сам печатаешь подобные названия? Вручную или через автокомплит? ИМХО длинность названия как раз и провоцирует пользоваться автокомплитом, а он как раз создает благодатную почву для таких ошибок.
Re[6]: Как поймать тестами такой баг?
От: Aikin Беларусь kavaleu.ru
Дата: 18.10.10 12:21
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А ты как сам печатаешь подобные названия? Вручную или через автокомплит? ИМХО длинность названия как раз и провоцирует пользоваться автокомплитом, а он как раз создает благодатную почву для таких ошибок.

код чаще читают, чем пишут

Стив МакКонел. Совершенный код


Во-вторых, здесь неверно выбрано название функции, вернее порядок слов в ней. Что уже неоднократно обсуждалось.

СУВ, Aikin
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
Re: Как поймать тестами такой баг?
От: AlexVinS Россия  
Дата: 20.10.10 12:30
Оценка:
Здравствуйте, MozgC, Вы писали:


MC>Но вопрос в том — как лучше тестировать чтобы такая ошибка обнаружилась. Ведь если для каждой функции писать кучу тестов и код, который проверяет как изменилось состояние БД (не затронулись ли другие строки и таблицы), то с ума можно сойти (я все-таки не маньяк-тестировщик, тесты в основном пишу только на наиболее критичные для бизнеса, либо сложные функции). Можно ли как-то проще?


первое что пришло на ум

1) Ослабить связь между слоями логики и доступа к данным, так чтобы ко всем XXXAccessor можно было MOK-объекты сделать. (можно и на слой ниже)
2) дальше само собой получится, что CustshipmentsAccessor.SetShipmentPricesForCustomer будет ожидаемым вызовом в тесте
3) НО это не спасет от случая когда 2 раза и в коде и в тесте будет вызов не того метода.


Умный человек знает не многое, но нужное
Re: Как поймать тестами такой баг?
От: Mr.Delphist  
Дата: 13.12.10 15:12
Оценка:
Здравствуйте, MozgC, Вы писали:

Для себя выработал правило: не должно быть в интерфейсе имен вида
  1. CommonName
  2. CommonNameExtra

Допустимы только непустые суффиксы:
  1. CommonNameOne
  2. CommonNameTwo
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.