Как перехватить возвращаемое значение действия gmock - PullRequest
0 голосов
/ 17 мая 2019

Я тестирую класс с фабрикой. Фабрика издевается с помощью гугл макета. Я использовал action и WillByDefault (), чтобы позволить фиктивной фабрике создавать примеры объектов и возвращать на них указатели. В тесте я прошу мой класс создать объект, используя фабрику с надписью и вернуть указатель на созданный объект. Я хочу убедиться, что указатель, возвращаемый из класса, совпадает с указателем, возвращаемым фиктивной фабрикой классу.

Допустим, у меня есть классная собака, собачья фабрика и питомник, который использует фабрику.

class dog;

class dogFactory{
    dog* makeDog() { return new dog; }
}

ACTION(makeDogInMock){ return new dog; }

class factoryMock : public factory{
    MOCK_METHOD1(makeDog, dog*());
}

class kennel{
    public:
    dog* dogInKennel;
    dogFactory factory;

    void putDogInKennel(){
        this->dogInKennel = factory.makeDog();
    }

    dog* getDogInKennel(){
        return this->dogInKennel;
    }

}

Затем в конструкторе тестов я использую действие как операцию по умолчанию:

ON_CALL(factoryMock, dog(_)).WillByDefault(makeDogInMock)

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

1 Ответ

0 голосов
/ 20 мая 2019

В вашем примере это никогда не будет собака, которую вы указали в действии по умолчанию, потому что дизайн вашей системы неправильный (если вы хотите протестировать ее с заводским макетом, конечно).Внутри вашей системы (kennel) вы должны хранить не конкретный объект фабрики, а указатель на интерфейс фабрики.Это называется инъекцией зависимости.Ваш пример может быть изменен следующим образом:

class Dog{};

class IDogFactory {
public:
    virtual ~IDogFactory() = default;
    virtual Dog* makeDog() = 0;
};

class DogFactory: public IDogFactory {
public:
    ~DogFactory() override = default;
    Dog* makeDog() override {
        return new Dog;
    }
};

class DogFactoryMock: public IDogFactory {
public:
    MOCK_METHOD0(makeDog, Dog*());
};

class Kennel {
public:
    explicit Kennel(IDogFactory* factory): factory_(factory) {}
    void putDogInKennel(){
        dogInKennel_ = factory_->makeDog();
    }
    Dog* getDogInKennel(){
        return dogInKennel_;
    }
private:
    Dog* dogInKennel_;
    IDogFactory* factory_;
};

using testing::Return;

TEST(xxx, yyy) {
    Dog d;
    DogFactoryMock factoryMock;
    ON_CALL(factoryMock, makeDog()).WillByDefault(Return(&d));
    Kennel sut(&factoryMock);
    sut.putDogInKennel();
    Dog* dPtr = sut.getDogInKennel();
    std::cout << (dPtr == &d) << std::endl;  // outputs "true"
}

IDogFactory - это интерфейс к фабрике, который может создать объект Dog.Как именно выполняется создание Dog, зависит от заводской реализации, но ваша система не зависит от нее.Таким образом, в производстве вы можете создать свой Kennel, передав указатель на DogFactory, в то время как в тестировании вы можете передать указатель на DogFactoryMock.В этом примере я использовал необработанные указатели на объекты в стеке, но я рекомендую вместо этого использовать std::shared_ptr.И для типа возврата с фабрики, и для фабричного указателя внутри вашей системы.

...