簡體   English   中英

如何使用 Google Test 測試 EXE?

[英]How to test an EXE with Google Test?

我在 Visual Studio 中有一個 C++ 項目,並添加了另一個專用於測試的項目。 這兩個項目都是 EXE(控制台應用程序)。 那么如何在第二個項目中使用第一個項目呢?

只是為了澄清,如果第一個項目是一個可以簡單地包含在第二個項目中的庫,那么這里的問題將是不言而喻的,但是作為一個 EXE,這就是問題所在。

根據您的評論,您有一個 C++ 控制台應用程序 ( MyApp) ,您已經為其開發了一些特定於應用程序的類,您希望在 Visual Studio 中使用 googletest 對這些類進行單元測試。 如何?

正如你所說,如果你想對一個進行單元測試,這樣做的方法是顯而易見的。 你會:

  • 1) 創建一個項目來創建單元測試應用程序 ( UnitTest )。
  • 2) 配置包含搜索目錄,以便編譯器可以找到庫的頭文件。
  • 3) 配置 library-search 目錄,以便鏈接器可以找到庫本身。
  • 4) 將庫本身添加到鏈接器輸入。
  • 5) 使UnitTest項目依賴於庫項目,以便構建UnitTest確保MyApp是最新的。
  • 6) 根據 googletest 文檔編寫UnitTest應用程序。

但是由於您要進行單元測試的類是特定於MyApp ,因此您沒有任何庫。

對此的回答是:您沒有包含要進行單元測試的類的庫? 所以做一個!

這樣你就可以使用 3 個項目:-

  • MyAppLib ,生成包含要進行單元測試的所有功能的庫。
  • MyApp ,生成與當前相同的可執行文件,但鏈接MyAppLib
  • UnitTest ,生成對MyAppLib單元測試的可執行文件,也鏈接MyAppLib

但是,如果您不喜歡演習中士的回答,您可以解決它。

從通常的構建系統的角度(設計到 Visual Studio 的角度來看), MyApp項目的重要輸出是構建目標 - .exe 生成的.obj文件只是中間的副產品。 VS 不支持將這些副產品視為依賴項目的自動鏈接器輸入,並且如果依賴項目也是同類的.exe - 就像你的情況一樣 - 那么這種自動鏈接無論如何都是不可能的,因為主要入口點將被多重定義。

但從單元測試的角度來看,情況正好相反。 .exe ,而(某些) .obj文件全部或部分包含您要進行單元測試的類的實現。 在類foofoo.h定義並在foo.cpp實現的foo.cppUnitTest的鏈接中需要目標文件foo.obj

為簡單起見,假設MyApp僅使用一個特定於應用程序的類foo ,在foo.h定義並在foo.cpp實現。 然后您有兩種構建UnitTest選項。

  • a) 您可以將foo.cpp添加到UnitTest的源文件中。 當然不要復制 只需從MyApp的源文件夾中添加一個現有項目 然后你就完成了,但是這門課程的缺點是foo.cppUnitTest項目中會受到不利的編輯。

  • b) 您可以將foo.obj鏈接UnitTest所需的靜態庫,並按照上面的步驟 1) - 6) 進行操作。 這尤其意味着在步驟 3) 中, UnitTest的 {Debug|Release} 構建配置了包含\\path\\to\\MyApp\\{Debug|Release} (相對或絕對形式)的庫搜索目錄。

實際上,對於選項 b),很可能有多個來自MyApp .obj文件必須在UnitTest鏈接,並且它們的數量很可能會隨着時間的推移而增加。 維護UnitTest的正確鏈接可能會成為一件苦差事,您可能會得出結論,畢竟演習中士是對的。

要看。 Google Test(主要)是一個單元測試框架(過度簡化,測試類)。 您絕對可以將 is 用於其他類型的測試,但它沒有用於其他類型測試的“內置”功能,您必須自己編寫。

如果您嘗試系統測試您的可執行文件,則可以運行該過程。 如果您使用的是多平台系統或已經有 boost 依賴,我建議使用 Boost.Process。 否則,請看這里: 使用 stdin stdout 和 stderr 啟動 exe/進程?

您編寫的“測試”將調用可執行文件,並可以相應地輸入標准輸入或標准輸出。

例如:

std::string path_to_exectuable = "thepath";
TEST(FooTester,CheckHelpScriptReturns0)
{
 using bp =::boost::process; 
 std::vector<std::string> args; args.push_back("--help");
 bp::context ctx; 
 ctx.stdout_behavior = bp::capture_stream(); 

 bp::child c = bp::launch(exec, args, ctx); 
 bp::status s = c.wait(); 
 ASSERT_TRUE(s.exited())<<"process didn't exit!";
 ASSERT_EQ(s.exit_status(),0)<<"Help didn't return 0";
}

我處於類似的情況,我的設置方式可以有效地實現與 Mike Kinghan 的答案相同的目標,就編譯器而言,但從用戶的角度來看,這是一種不同的方式。

我所做的是創建一個我稱之為“測試”的自定義配置。 您可以通過打開項目設置,選擇“配置管理器...”並在配置選擇框中選擇“新建...”來創建新配置。

出現提示時,我選擇從默認的“調試”配置中復制設置,以便我可以在測試中使用調試器,就像我在“調試”配置中一樣。

在新的測試配置下,我將編譯器和鏈接器的選項設置為像往常一樣使用 google 測試。

屬性的重要變化是我定義了一個我稱之為“TESTING”的預處理器變量。

我重寫了我的“main.cpp”,看起來像這樣:

...
// includes
// functions
// whatever
...

#ifdef TESTING
#include <gtest/gtest.h>
#endif

int main(int argc, char **argv) {
   #ifdef TESTING
   ::testing::InitGoogleTest(&argc, argv);
   int val = RUN_ALL_TESTS();
   getchar();  // not necessary, but keeps the console open
   return val;
   #endif    

   // rest of main() as normal...
}

我想表明的是,我只在定義main地方更改了幾行,我不必在整個文件中進行粗略的更改。

現在這一切都設置好了,我只是為我的測試創建了一個新的源文件夾,並在其中創建了“.cpp”文件。 為了避免普通的可執行文件膨脹,我用檢查 TESTING 變量來包裝這些文件,所以我有這樣的東西:

tests/Test.cpp:

#ifdef TESTING

#include <gtest/gtest.h>

#include "my_class_header.h"

TEST(TestMyClass, test_something) {
    // perform some test on class
} 

#endif

我認為這些文件在 Debug 和 Release 配置下仍然會被編譯器“命中”,因此大量這些文件可能會減慢構建速度,但 Debug 和 Release 對象不會因測試代碼而變得臃腫。

兩個要點是:

  • 使用這種方法,測試代碼仍然與應用程序代碼分開組織,但它仍然駐留在同一個 Visual Studio 項目中,這可能有益也可能無益。 我個人喜歡不必管理/擔心第二個項目。
  • 就像 Mike Kinghan 所說的那樣,自己管理和鏈接.obj文件可能會成為一件苦差事,但通過使用這種方法,默認的 Visual Studio 設置會為您管理。

一個缺點是所有目標文件的有效冗余副本將在“測試”輸出目錄中創建。 有了更多的配置,肯定有一種方法可以“共享”調試目標文件,但我沒有理由走那么遠。

這是一種非常簡單的方法,可能比將您的應用程序重構為單獨的庫和主程序要容易得多。 我不喜歡使用預處理器 wankery,但在這種情況下,它相當簡單,沒有太多代碼膨脹,並且完全完成了它需要的功能。 您可以隨時以另一種方式觸發測試,而無需使用預處理器。

如果您對在不同項目中進行測試不是很嚴格,您可以在您的應用程序項目中編寫測試。 然后讓應用程序在接收到某些命令行參數時執行測試,否則執行正常的應用程序邏輯,即

int main(int argc, char* argv[])
{
    if (argc >= 2 && std::string(argv[1]) == "--tests")
    {
        ::testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }
    else
    {
        // Application logic goes here
    }
}

TEST(ExampleTests, TestSQRTCalculation) // assuming all the right headers are included
{
    EXPECT_NEAR(2.0, std::sqrt(4.0), 0.000001);
}

這避免了僅為測試目的創建不必要的庫,盡管如果結構正確,您仍然可以這樣做。 缺點是測試代碼會進入您要發布的可執行文件。 如果你不想要,我猜你需要一個額外的配置,它指定一個預處理器指令來禁用測試。

調試測試或在構建后自動運行它們很容易,只需分別指定“--tests”作為調試參數或在構建后命令行中。

如果你想測試一個控制台應用程序,你可以運行一個測試,打開一個控制台窗口並運行第一個應用程序的 exe 文件。 然后在您的 googletest 中捕獲您剛剛運行的 exe 的標准輸出。

[為了更好地控制第一個應用程序,您可能需要將第一個應用程序解析參數發送給它,例如 -x 之類的標志或您需要的任何東西。]

我准備了一個 github 存儲庫,其中包括與 Mike 的“drill-sergeant”建議並行的 Visual Studio 2015 解決方案。 您可以直接使用它,無需任何額外的要求或依賴。

https://github.com/fuatcoskun/GoogleTestVS2015

我希望它有幫助...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM