Обнаружение мрачного вывода в Google UnitTest

Ниже приведена функция, которую я имею в моем исходном файле

cv::Mat* Retina::Preprocessing::create_mask(const cv::Mat *img, const uint8_t threshold) {

    LOG_IF(ERROR, img->empty()) << "The input image is empty. Terminating Now!!";

    cv::Mat green_channel(img->rows(), img->cols(), CV_8UC1); /*!< Green channel. */

    /// Check number of channels in img and based on that find out the green channel.
    switch (img->channels()){
        /// For 3 channels, it is an RGB image and we use cv::mixChannels().
        case(3): {
            int from_to[] =  {1,0};
            cv::mixChannels(img, 1, &green_channel, 1, from_to, 1);
            break;
        }
        /// For a single channel, we assume that it is the green channel.
        case(1): {
            green_channel = *img;
            break;
        }
        /// Otherwise we are out of clue and throw an error.
        default: {
            LOG(ERROR)<<"Number of image channels found = "<< img->channels()<<". Terminating Now!!";
            return nullptr; /*!< (unreachable code) Only given for completion */
        }

    }

    cv::Mat mask(img->rows(), img->cols(), CV_8UC1);/*!< Empty mask image */

    if (threshold == 0)/// Otsu's threshold is used
        cv::threshold(green, mask, threshold, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    else /// We can use the provided threshold value
        cv::threshold(green, mask, threshold, 255, CV_THRESH_BINARY);

    LOG_IF(ERROR, mask.empty())<< "After thresholding, image became empty. Terminating Now!!";



    std::vector<std::vector<cv::Point>> contours;

    /// Get the contours in the binary mask.
    cv::findContours(mask, *contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
    size_t max_index{};
    double prev_area{};
    size_t index{};

    /// Lambda function for a convenient one-liner std::for_each. SEE BELOW.
    lambda_max_index = [max_index, prev_area, index] (std::vector<cv::Point> c){
        double new_area { cv::contourArea(c) };
        max_index = (new_area > prev_area) ? max_index = index : max_index;
        ++index;
    };

    /// For each contour compute its area, and over the loop find out the largest contour.
    std::for_each(contours.begin(), contours.end(), lambda_max_index());

    /// Iterate over each point and test if it lies inside the contour, and drive in it.
    for(size_t row_pt = 0; row_pt < mask_out.rows(); ++row_pt){
        for(size_t col_pt = 0; col_pt < mask_out.cols(); ++col_pt){
            if (cv::pointPolygonTest(contours[max_index], cv::Point(row_pt, col_pt))>=0)
                mask[row_pt, col_pt] = 255;
            else
                mask[row_pt, col_pt] = 0;
        }
    }
    return &mask;
}

Ниже приведен файл Google Unit Test, который я написал. Это моя самая первая попытка с GoogleTest.

#include"PreProcessing.hxx"
#include<opencv2/highgui/highgui.hpp>
#include<gtest/gtest.h>

TEST(Fundus_Mask_Creation, NO_THRESHOLD) {

    cv::Mat img(cv::imread(std::string("../data/test_img.jpg")));

    cv::Mat* mask = Retina::Preprocessing::create_mask(&img);

    ASSERT_TRUE(!(mask->empty()));

    std::string winname("Input Image");
    cv::namedWindow(winname);

    cv::imshow(winname, img);
    cv::waitKey(800);

    cv::destroyWindow(winname);

    winname = "Fundus Mask";
    cv::namedWindow(winname);

    cv::imshow(winname, *mask);
    cv::waitKey(800);
}

    TEST(Fundus_Mask_Creation, THRESHOLD) {

        cv::Mat img(cv::imread(std::string("../data/test_img.jpg")));

        std::uint8_t threshold{10};
        cv::Mat* mask = Retina::Preprocessing::create_mask(&img, threshold);

        ASSERT_TRUE(!(mask->empty()));

        std::string winname("Input Image");
        cv::namedWindow(winname);

        cv::imshow(winname, img);
        cv::waitKey(800);

        cv::destroyWindow(winname);

        winname = "Fundus Mask";
        cv::namedWindow(winname);

        cv::imshow(winname, *mask);
        cv::waitKey(800);
    }

Я также хотел бы проверить для случая, когда логи, что "Number of image channels found = "<< img->channels()<<". Terminating Now!!!";

Как я могу написать модульный тест, который будет успешно выполнен (т. Е. Исходный исходный файл выдаст ошибку FATAL), если я предоставлю ему вход, который приведет к тому, что вышеприведенное сообщение будет правильно зарегистрировано?

1 ответ

Решение

Вам нужно издеваться (googlemock), чтобы достичь этого. Чтобы включить mocking, создайте тонкий класс-оболочку для вызовов glog вместе с интерфейсом, от которого этот класс будет наследоваться (это необходимо для включения mocking). Вы можете использовать это как руководство:

class IGlogWrapper {
public:
    ...
    virtual void LogIf(int logMessageType, bool condition, const std::string &message) = 0;
    ...
};

class GlogWrapper : public IGlogWrapper {
public:
    ...
    void LogIf(int logMessageType, bool condition, const std::string &message) override {
        LOG_IF(logMessageType, condition) << message;
    }
    ...
};

Теперь создайте фиктивный класс:

class GlogWrapperMock : public IGlogWrapper {
public:
    ...
    MOCK_METHOD3(LogIf, void(int, bool, const std::string &));
    ...
};

и сделай свой Retina::Preprocessing класс содержит указатель на IGlogWrapper и сделать запись звонков через этот интерфейс. Теперь вы можете использовать внедрение зависимостей для перехода к Retina::Preprocessing класс указатель на класс реального регистратора GlogWrapper который будет использовать glog, в то время как в тестах вы передаете указатель на фиктивный объект (экземпляр GlogWrapperMock). Таким образом, вы можете создать изображение в тесте, который будет иметь два канала, и установить ожидания для этого фиктивного объекта для вызова функции LogIf в таком случае. В следующем примере публичный метод используется для внедрения используемого регистратора:

using namespace testing;

TEST(Fundus_Mask_Creation, FAILS_FOR_TWO_CHANNEL_IMAGES) {

    // create image with two channels
    cv::Mat img( ... );

    GlogWrapperMock glogMock;
    Retina::Preprocessing::setLogger(&glogMock);

    std::string expectedMessage = "Number of image channels found = 2. Terminating Now!!";
    EXPECT_CALL(glogMock, LogIf(ERROR, _, expectedMessage).WillOnce(Return());

    cv::Mat* mask = Retina::Preprocessing::create_mask(&img);

    // Make additional assertions if necessary
    ...
}

Дополнительную информацию о насмешках можно найти в документации: https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md#getting-started Также обратите внимание, что опубликованные вами два модульных теста не имеет особого смысла, так как вы загружаете изображение с диска, а также делаете дополнительные вызовы после подтверждения. Модульное тестирование должно быть кратким, быстрым и изолированным от окружающей среды. Я хотел бы предложить дополнительное чтение о модульных тестах, Интернет полон ресурсов. Надеюсь это поможет!

Другие вопросы по тегам