2016-06-10 11 views
1

Die folgende Erkennen ist eine Funktion, die ich in meiner Quelldateieine glog Ausgabe in einem 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; 
} 
haben

Hier finden Sie eine Google-Unit-Test-Datei habe ich geschrieben. Dies ist mein allererster Versuch mit 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); 
    } 

ich auch für den Fall testen möchten, wo glog Protokolle, die "Number of image channels found = "<< img->channels()<<". Terminating Now!!!";

Wie kann ich einen Komponententest schreiben, die erfolgreich laufen würde (Datei dh die ursprüngliche Quelle ein fataler Fehler wäre log) , wenn ich eine Eingabe mache, die dazu führt, dass die obige Nachricht richtig geloggt wird?

Antwort

2

Sie brauchen Spott (googlemock), um das zu erreichen. Erstellen Sie eine dünne Wrapper-Klasse für glog Aufrufe, zusammen mit einer Schnittstelle, von der diese Klasse erben wird (Sie müssen dies aktivieren, um Mocking zu ermöglichen). Sie können dies als Richtlinie:

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; 
    } 
    ... 
}; 

Jetzt ein Mock-Klasse erstellen:

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

und machen Sie Ihre Retina::Preprocessing Klasse einen Zeiger auf IGlogWrapper halten und die Protokollierung Anrufe über diese Schnittstelle machen. Jetzt können Sie die Abhängigkeitsinjektion verwenden, um einen Zeiger auf eine echte Loggerklasse GlogWrapper Klasse Retina::Preprocessing zu übergeben, die glog verwendet, während Sie in Tests einen Zeiger auf ein Mock-Objekt übergeben (Instanz GlogWrapperMock). Auf diese Weise können Sie in einem Test mit zwei Kanälen ein Bild erstellen und in diesem Fall die Funktion LogIf für dieses Mock-Objekt festlegen. Im folgenden Beispiel wird eine öffentliche Methode einen Logger injizieren zu verwenden:

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 
    ... 
} 

Für weitere Informationen über spöttisch die Dokumentation prüfen: https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md#getting-started Beachten Sie auch, dass die beiden Komponententests Sie gepostet haben nicht viel machen Sinn, wenn Sie ein Bild von der Festplatte laden und nach der Assertion weitere Anrufe tätigen. Der Komponententest sollte präzise, ​​schnell und von der Umgebung isoliert sein. Ich würde vorschlagen, zusätzliche Informationen über Komponententests zu lesen, das Internet ist voller Ressourcen. Hoffe das hilft!

+0

ja. es tat es. Vielen Dank. ich hab viel gelernt. –

+1

@UjjwalAryan Sie sind herzlich willkommen! Bitte überlegen Sie, die Antwort zu verbessern, wenn es hilfreich war, als Zeichen der Wertschätzung. –

+0

Dies ist die Antwort, die ich geschrieben hätte :), aber ich werde darauf hinweisen, dass eine andere Möglichkeit, Aufrufe an eine API abzufangen und zu erfassen, die Verwendung von Link-Time-Mocks ist. Dies sind Funktionen mit der gleichen Signatur wie die reguläre Protokoll-API, aber mit einer anderen Implementierung, die wie die Mocks funktioniert: Sie zeichnet Interaktionen auf und liefert die erwarteten Ergebnisse. Link-Time-Mocks sind eher eine C-Technik als C++, bei denen Schnittstellen besser mit der Sprache funktionieren. – legalize