2016-06-10 2 views
1

Ниже функция у меня в исходном файлеДетектирование выход GLog в 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 я написал. Это моя первая попытка с 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); 
    } 

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

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

ответ

2

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

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 Кроме того, обратите внимание, что два модульных тестов вы размещены не делают много когда вы загружаете изображение с диска, а также делаете дополнительные вызовы после утверждения. Единичный тест должен быть кратким, быстрым и изолированным от окружающей среды. Я бы предложил дополнительное чтение об модульных тестах, в Интернете полно ресурсов. Надеюсь это поможет!

+0

Да. он сделал. тебя много. Я многому научился. –

+1

@UjjwalAryan Добро пожаловать! Пожалуйста, подумайте над тем, чтобы ответить, если это было полезно, в знак признательности. –

+0

Это ответ, который я бы написал :), но я укажу, что другой способ перехватить и вызвать вызовы API - использовать макеты ссылок-времени. Это функции с той же сигнатурой, что и обычный API журналов, но с другой реализацией, которая действует как mocks: она регистрирует взаимодействия и обеспечивает ожидаемые результаты. Link-time mocks - это скорее метод C, чем C++, где, я думаю, интерфейсы лучше работают с языком. – legalize

Смежные вопросы