Я заинтересован в тестировании функции navigationFoo ниже:
virtual void navigateFoo(const vector<Node>& nodes)
{
// find the foo node in the list of nodes
Nodes::const_iterator fooNodeI = findFooNode(nodes);
// if we have found the foo node
if(fooNodeI!=nodes.end())
{
// the id for retrieving the associated Foo Container from the cache
std::string id = getCacheIdentifier(*fooNodeI);
// the Foo Container associated with the Foo Node
FooContainer& container = _fooContainerCache->get(id);
// the name of the Foo item within the Foo Container
std::string name = getName(*fooNodeI);
// if foo is not found in the associated container, add it
if(findFoo(name, container)==container.end())
{
container.push_back( createFoo(getData(*fooNodeI)) );
}
}
}
Узел имеет тип boost::variant, где этот вариант содержит типы Foo1, Foo2, Bar1 и Bar2 и т. д.
Бесплатная функция findFooNode
использует шаблон посетителя для поиска узла Foo (типа Foo1 или Foo2).
Бесплатная функция getCacheIdentifier
также использует шаблон посетителя для поиска идентификатора кеша для узла Foo.
_fooContainerCache
— это инъекция зависимостей, над которой издеваются в моем модульном тесте.
getName снова бесплатная функция, как и createFoo
.
Все бесплатные функции сами проходят модульное тестирование и используются в других функциях моего кода.
Вещи легко тестируются вплоть до линии:
FooContainer& container = _fooContainerCache->get(id);
так как мне нужно только проверить с помощью макета, что ожидаемый идентификатор представлен функции получения.
Однако, чтобы протестировать код после этой строки, мне нужно проверить изменения, внесенные в FooContainer, возвращенные по ссылке из моего макета. Однако, если createFoo изменится в будущем, а я знаю, что это произойдет, это приведет к тому, что мне придется изменить свои модульные тесты как для createFoo, так и для navigationFoo. Однако, если бы вместо этого я должен был внедрить зависимость FooFactory, я бы избежал этой проблемы, выполнив вместо этого следующее:
container.push_back( _fooFactory->create( getData(*fooNodeI) ));
Затем я могу издеваться над этой функцией и в своем модульном тесте. Если поведение этого интерфейса изменится, мне не придется переписывать тесты для navigationFoo.
Однако, когда я писал createFoo, я никогда не считал естественным, что он должен быть реализован как интерфейс, поэтому теперь я чувствую, что добавляю интерфейс просто для того, чтобы иметь возможность писать более качественные тесты. И тогда возникает вопрос, должен ли быть интерфейс для каких-либо других моих бесплатных функций? Есть ли какие-то правила на этот счет?
navigateFoo
. Если кто-то совершит ошибку, то это поведение должно быть заметно, посколькуnavigateFoo
будет давать неправильные ответы. - person Billy ONeal   schedule 29.04.2013