Как избежать указателей с помощью Google Mock?

В нашем проекте мы используем Google Mock, но во многих местах мы делаем конструкции в нашем производственном коде только для того, чтобы классы были «мокабельными». Мы делаем это, потому что хотим использовать преимущества Google Mock, но, с другой стороны, мы бы предпочли более оптимальный производственный код. Следующий случай — это то, что мы делаем часто, и от него хотелось бы избавиться.

class A{
  public:
    void doSomething(); //Does something with _someB
    void setSomeB(B* mockedB); //This is only here for GMock
  private:
    B* _someB; //This should not be a pointer, it is a pointer only for GMock
}

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

Есть ли способ избежать этого? Разве мы не можем позволить B быть ограниченным в классе?

Спасибо


person W. Goeman    schedule 06.04.2012    source источник
comment
@TonyTheLion, который по-прежнему не заставит объект жить в стеке, он все равно будет указателем, и мне все равно понадобится установщик.   -  person W. Goeman    schedule 06.04.2012
comment
Google очень любит внедрение зависимостей. Имеет смысл, что вам было бы трудно использовать их среду тестирования без нее. Я настоятельно рекомендую вам посмотреть их серию видеороликов на YouTube The Clean Code Talks. Тот, который освещал основы их философии модульного тестирования, можно найти здесь: youtu.be/wEhu57pih5w   -  person cgmb    schedule 10.04.2012
comment
Вы можете позволить клиенту класса A создать B в стеке, а затем зависимость внедрить его в класс A в качестве ссылки. Кроме того, когда вы говорите об оптимальном производственном коде, это преждевременная оптимизация?   -  person User    schedule 27.04.2012


Ответы (1)


Если вы действительно не хотите, чтобы _someB хранился как указатель, можно было бы обернуть его объявление в командах препроцессора:

#ifdef MOCK_TEST
    B _someB;
#else
    MockB _someB;
#endif

Если вы этого не сделаете, нет простого способа поместить ожидания и/или утверждения gmock в _someB, поскольку это не будет экземпляром фиктивного объекта. Помимо уродства этого, у него также есть недостаток, заключающийся в том, что требуется дважды скомпилировать библиотеку, в которой находится Class A, один раз с определенным MOCK_TEST и один раз без него. Однако это устраняет необходимость в сеттере для _someB.

Даже если вы решите сохранить _someB в качестве указателя, возможно, лучшим вариантом, чем создание общедоступного установщика, будет объявить тестовый класс дружественным классом A, чтобы позволить тесту напрямую устанавливать и получать доступ к _someB.


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

person Fraser    schedule 06.04.2012
comment
Это действительно хороший способ обойти сеттер, но он по-прежнему требует специального кода в классе, от которого я все время хотел избавиться. Я думаю, что идеального решения этой проблемы просто не существует. Я приму этот ответ, если он дает разумное решение. Спасибо за ведущий комментарий с подчеркиванием. Такой я точно запомню! - person W. Goeman; 08.04.2012
comment
@W.Goeman: в качестве дополнения к проблеме с подчеркиванием, обратите внимание, что Руководство по стилю Google C++ рекомендует использовать символы подчеркивания в конце. - person User; 27.04.2012