Home > The Unit Test Framework > Tutorials > Hello the testing world
PrevNext

Hello the testing world or beginner's introduction into testing using the Unit Test Framework

How should a test program report errors? Displaying an error message is an obvious possibility:
測試程序如何報告錯誤呢?打印錯誤信息是一種很顯然的可能:

if( something_bad_detected )
  std::cout << "something bad has been detected" << std::endl;

But that requires inspection of the program's output after each run to determine if an error occurred. Since test programs are often run as part of a regression test suite, human inspection of output to detect error messages is time consuming and unreliable. Test frameworks like GNU/expect can do the inspections automatically, but are overly complex for simple testing.
但那需要在每次運行後觀察程序的輸出來判斷是否有錯誤。 因為測試程序會作為回歸測試套件的一部分經常被運行,肉眼觀察輸出判斷錯誤信息是耗時而不可靠的。 測試框架如 GNU/expect 能夠自動檢察輸出,但對於簡單的測試來說太過於複雜了。

A better simple way to report errors is for the test program to return EXIT_SUCCESS (normally 0) if the test program completes satisfactorily, and EXIT_FAILURE if an error is detected. This allows a simple regression test script to automatically and unambiguous detect success or failure. Further appropriate actions such as creating an HTML table or emailing an alert can be taken by the script, and can be modified as desired without having to change the actual C++ test programs.
更簡單的錯誤方式是當測試程序令人滿意地完成後返回 EXIT_SUCCESS (通常為 0),如果有錯誤被檢測到則返回 EXIT_FAILURE。 這可以允許簡單的回歸測試腳本自動運行並且無歧義地檢查通過與否。 更進一步的操作例如創建 HTML 表格或 email 發送通知都可以通過腳本創建,並修改而不需要修改實際的 C++ 測試程序。

A testing protocol based on a policy of test programs returning EXIT_SUCCESS or EXIT_FAILURE does not require any supporting tools; the C++ language and standard library are sufficient. The programmer must remember, however, to catch all exceptions and convert them to program exits with non-zero return codes. The programmer must also remember to not use the standard library assert() macro for test code, because on some systems it results in undesirable side effects like a message requiring manual intervention.
基於返回 EXIT_SUCCESS 或 EXIT_FAILURE 這樣策略的測試協議並不需要支持的工具;C++ 語言和標準庫就已經足夠了。 然而,程序員必須記得捕獲所有異常並將它們轉換為非零的程序返回代碼。 程序員還必須記得不能在測試代碼中使用標準庫的 assert() 宏,因為在某些系統上這會導致不可預料的副作用,如需要用戶手工干預的消息。

The Boost Test Library's Unit Test Framework is designed to automate those tasks. The library supplied main() relieves users from messy error detection and reporting duties. Users could use supplied testing tools to perform complex validation tasks. Let's take a look on the following simple test program:
Boost Test 庫的 Unit Test Framework 被設計用來使這些任務自動化。 庫提供了 main() 將用戶從繁瑣的錯誤檢測報告中解放出來。用戶可以使用提供的測試工具完成複雜的驗證任務。 我們看一下下面簡單的測試程序:

#include <my_class.hpp>

int main( int, char* [] )
{
    my_class test_object( "qwerty" );

    return test_object.is_valid() ? EXIT_SUCCESS : EXIT_FAILURE;
}

There are several issues with above test.
下面的測試有一些問題。

  1. You need to convert is_valid result in proper result code.
    你需要將 is_valid 的結果轉換為適當的結果代碼。
  2. Would exception happen in test_object construction of method is_valid invocation, the program will crash.
    如果在 test_object 的構造或 is_valid 調用過程中拋出異常,程序會崩潰。
  3. You won't see any output, would you run this test manually.
    如果手動運行測試,將不會看到任何輸出。

The Unit Test Framework solves all these issues. To integrate with it above program needs to be changed to:
Unit Test Framework 解決了所有這些問題。要使用它上面的程序需要如下修改:

#include <my_class.hpp>
#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( my_test )
{
    my_class test_object( "qwerty" );

    BOOST_CHECK( test_object.is_valid() );
}

Now, you not only receive uniform result code, even in case of exception, but also nicely formatted output from BOOST_CHECK tool, would you choose to see it. Is there any other ways to perform checks? The following example test program shows several different ways to detect and report an error in the add() function.
現在,不僅在發生異常的情況下你可以得到一致的結果代碼,同時如果你想要看到 BOOST_CHECK 工具的輸出,你可以很漂亮地格式化它們。 還有別的方法來執行檢查嗎? 下面的示例測試程序展示了不同的方法在 add() 函數中檢查和報告錯誤。

#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>

int add( int i, int j ) { return i+j; }

BOOST_AUTO_TEST_CASE( my_test )
{
    // seven ways to detect and report the same error:
    BOOST_CHECK( add( 2,2 ) == 4 );        // #1 continues on error

    BOOST_REQUIRE( add( 2,2 ) == 4 );      // #2 throws on error

    if( add( 2,2 ) != 4 )
      BOOST_ERROR( "Ouch..." );            // #3 continues on error

    if( add( 2,2 ) != 4 )
      BOOST_FAIL( "Ouch..." );             // #4 throws on error

    if( add( 2,2 ) != 4 ) throw "Ouch..."; // #5 throws on error

    BOOST_CHECK_MESSAGE( add( 2,2 ) == 4,  // #6 continues on error
                         "add(..) result: " << add( 2,2 ) );

    BOOST_CHECK_EQUAL( add( 2,2 ), 4 );	  // #7 continues on error
}

(1)

This approach uses the BOOST_CHECK tool, which displays an error message (by default on std::cout) that includes the expression that failed, the source file name, and the source file line number. It also increments the error count. At program termination, the error count will be displayed automatically by the Unit Test Framework.
這個方法使用 BOOST_CHECK 工具,打印 (默認在 std::cout) 包含失敗表達式、源文件名稱、源文件行號的錯誤信息。 它同樣增加錯誤數量。程序終止時,錯誤數量會被 Unit Test Framework 自動顯示。

(2)

This approach uses the BOOST_REQUIRE tool, is similar to approach #1, except that after displaying the error, an exception is thrown, to be caught by the Unit Test Framework. This approach is suitable when writing an explicit test program, and the error would be so severe as to make further testing impractical. BOOST_REQUIRE differs from the C++ Standard Library's assert() macro in that it is always generated, and channels error detection into the uniform Unit Test Framework reporting procedure.
這個方法使用 BOOST_REQUIRE 工具,類似於 #1,除了在打印錯誤後,拋出一個異常被 Unit Test Framework 捕獲。 這個方法在編寫直接的測試程序,且錯誤非常嚴格,以致於後面的測試沒有意義時適用。 BOOST_REQUIRE 和 C++ 標準庫的 assert() 不同,它總是被生成,並且將由 Unit Test Framework 生成一致的錯誤報告。

(3)

This approach is similar to approach #1, except that the error detection and error reporting are coded separately. This is most useful when the specific condition being tested requires several independent statements and/or is not indicative of the reason for failure.
方法類似於 #1,除了錯誤檢測和錯誤報告是獨立記錄的。 當被測試的特定情況需要一些獨立描述並且 / 或者並不是失敗原因的情況下是最有用的。

(4)

This approach is similar to approach #2, except that the error detection and error reporting are coded separately. This is most useful when the specific condition being tested requires several independent statements and/or is not indicative of the reason for failure.
這個方法類似於 #2,除了錯誤檢測和錯誤報告是獨立記錄的。 當被測試的特定情況需要一些獨立描述並且 / 或者並不是失敗原因的情況下是最有用的。

(5)

This approach throws an exception, which will be caught and reported by the Unit Test Framework. The error message displayed when the exception is caught will be most meaningful if the exception is derived from std::exception, or is a char* or std::string.
這個方法拋出一個異常,將被 Unit Test Framework 捕獲並報告。 如果異常派生自 std::exception 或是一個 char* 或 std::string,當異常被捕獲時打印的錯誤信息將會是有意義的。

(6)

This approach uses the BOOST_CHECK_MESSAGE tool, is similar to approach #1, except that similar to the approach #3 displays an alternative error message specified as a second argument.
這個方法使用 BOOST_CHECK_MESSAGE 工具,和 #1 類似,除了類似於 #3 的部分將打印作為第二個參數的錯誤信息。

(7)

This approach uses the BOOST_CHECK_EQUAL tool and functionally is similar to approach #1. This approach is most attractive for checking equality of two variables, since in case of error it shows mismatched values.
這個方法使用 BOOST_CHECK_EQUAL 工具,其功能和 #1 類似。 這是檢查兩個變量是否相等的最有用的方法,因為如果不相等會顯示不匹配的值。


PrevUpHomeNext