Тест Google и правильный дизайн макетных классов для уменьшения избыточности

#googletest #googlemock

Вопрос:

Рассмотрим базовый класс B и два наследующих класса D1 и D2. B имеет общедоступную функцию под названием «запуск», которая вызывает чисто виртуальную функцию «запуск» при условии, возвращаемом функцией «someCondition». Запуск функции реализован классами D1 и D2, каждый класс использует собственную логику, представленную функциями «d1Condition» и «d2Condition».

Пример кода:

 class B {
public: 
    virtual ~B() {}
    void start() { if (someCondition()) run(); } 
    virtual bool someCondition() { return true; } 
protected:
    virtual void run() = 0;
};

class D1 : public B {
public:
    D1();
    virtual ~D1() {}
    virtual bool d1Condition() { return true; }
protected:
    virtual void run() {
        if (d1Condition()) {
            //some code
        }
    }
};

class D2 : public B {
public:
    D2();
    virtual ~D2() {}
    virtual bool d2Condition() { return true; }
protected:
    virtual void run() {
        if (d2Condition()) {
            //some code
        }       
    }
};
 

Я хотел бы написать модульный тест для сценария «запуск» для классов D1 и D2. Я могу написать макет класса для D1 и еще один для D2. Фиктивный класс для D1 будет иметь фиктивную функцию для условия d1, а фиктивный класс для D2 будет иметь фиктивную функцию для функции D2. Тем не менее, чтобы запустить сценарий, мне нужна другая функция макета для некоторого условия(). Этот фиктивный метод будет действовать одинаково для обоих тестов D1 и D2 — он должен возвращать значение true, чтобы была вызвана функция run.

Как мне избежать избыточности фиктивного метода для некоторых условий ?

Ответ №1:

Для меня вы реализовали шаблон стратегии. И D1, и D2 решают одну и ту же проблему, используя разные подходы. Просто создайте чистый виртуальный защищенный метод, вызываемый runCondition в базовом классе:

 class B {
public: 
    virtual ~B() = defau<
    void start() { if (someCondition()) run(); } 
    virtual bool someCondition() { return true; } 
protected:
    void run() {
        if(runCondition()) {
            // some code
        }
    }
    // each derived class needs to implement this step in a different way
    virtual bool runCondition() = 0;
};
 

Отсюда у вас есть 3 вещи, которые нужно проверить: класс B непосредственно, чтобы проверить это runCondition и run вызывается, когда start вызывается (например, с помощью частичного насмешки — вы можете создать PartialBMock , где someCondition и runCondition над кем будут насмехаться, и проверить, что происходит, когда start вызывается). Тогда вам нужно будет протестировать D1 и D2 их runCondition : т. е. посмотреть, при каких условиях run будут вызываться. Если эти runCondition реализации s трудно проверить — извлеките их в отдельные классы и используйте насмешки D1 и D2 тесты.