Доступ к защищенным функциям-членам из тестового кода на C ++ - PullRequest
11 голосов
/ 12 ноября 2009

Я ломал голову, пытаясь придумать лучший способ доступа к защищенной функции-члену из некоторого тестового кода на C ++, вот моя проблема:

//in Foo.h 
Class Foo
{
protected:
    void DoSomething(Data data);
}

//in Blah.h
Class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
Blah blah;
blah.foo.DoSomething(blah.data); // Here's my problem!

Некоторые возможные решения на данный момент:

Сделайте класс тестового кода другом Foo, но это загрязнит Foo тестовым кодом Сделать DoSomething публичной функцией Я рассмотрел создание тестовой оболочки для Foo, как предложено в этого поста , однако это не сработает, поскольку Blah содержит экземпляр Foo.

Все советы / идеи / мнения приветствуются!

Спасибо

Ответы [ 8 ]

16 голосов
/ 12 ноября 2009

Существует способ, который полностью разрешен Стандартом.

//in Foo.h 
class Foo
{
protected:
    void DoSomething(Data data);
};

//in Blah.h
class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
struct FooExposer : Foo {
  using Foo::DoSomething;
};

Blah blah;
(blah.foo.*&FooExposer::DoSomething)(blah.data);

Прочитайте запись Скрытые возможности C ++ для объяснения.


Вы можете написать макрос для вашего удобства (здесь есть скобки, чтобы вы могли использовать этот макрос также для типов, которые имеют запятую, например vector<pair<A, B>>):

#define ACCESS(A, M, N) struct N : get_a1<void A>::type { using get_a1<void A>::type::M; }

template<typename T> struct get_a1;
template<typename R, typename A1> struct get_a1<R(A1)> { typedef A1 type; };

Теперь материя становится

ACCESS((Foo), DoSomething, GetDoSomething);
Blah blah;
(blah.foo.*&GetDoSomething::DoSomething)(blah.data);
8 голосов
/ 12 ноября 2009

Хорошо, поскольку вы сказали, что это всего лишь тестовый код, я собираюсь предложить что-то серьезное, но сработает:

struct tc : protected Foo
{
    tc(Foo *foo, Data& data)
    {
        ((tc*)foo)->DoSomething(data);
    }
};

Blah blah;
tc t(&blah.foo, blah.data);
7 голосов
/ 12 ноября 2009

С одной стороны, не делай этого .

С другой стороны, вот игра:

#define protected public
#include "foo.h"
#undef protected

8 -)

А если серьезно, почему DoSomething() защищен? Возможно, потому что вызов этого из внешнего кода может что-то сломать. В этом случае вы не должны вызывать его из своих тестов.

3 голосов
/ 12 ноября 2009

Вместо того, чтобы определить private до public, рассмотрите , если определите дружбу , или еще лучше подумайте, если эта функция действительно должна принадлежать этому классу, возможно, этого будет достаточно иметь что-то в именованном / безымянном пространстве имен в cpp, а затем объявить в тестовом проекте.

В любом случае, проверьте эту ссылку, возможно, ваш фреймворк обеспечит аналогичную функциональность.

РЕДАКТИРОВАТЬ: Рассматривали ли вы наследование вашего тестового класса от вашего реального класса?

3 голосов
/ 12 ноября 2009

Я сделал

class Foo
{
protected:
    void DoSomething(Data data);
public:
    #ifdef TEST
    void testDoSomething(Data data);
    #endif
}

Затем скомпилируйте свои модульные тесты с g ++ -D TEST.

2 голосов
/ 12 ноября 2009

Используйте обертку следующим образом:

// Foo.h unchanged

// Blah.h unchanged

// test code
class FooTest : public Foo { friend void test(); }; // make friends

void test()
{
    Blah blah;
    static_cast<FooTest*>(&blah.foo)->DoSomething(blah.data); // Here's no problem!    
}
2 голосов
/ 12 ноября 2009

Вы можете использовать наследование с функциями пересылки:

class Foo
{
protected:
    void DoSomething(Data data);
}

class test_Foo : public Foo
{
public:
    void testDoSomething(Data data)
    {
        DoSomething(data);
    }
}
1 голос
/ 12 ноября 2009

Если это строго тестовый код, вы можете сделать ...

#define protected public
#include "Foo.h"

// test code

#undef protected
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...