2008-08-19 25 views
9

Trong hầu hết các dự án tôi sử dụng nhiều tuyên bố ASSERTION C++ của tôi như sau:Test Cases VS tuyên bố ASSERTION

int doWonderfulThings(const int* fantasticData) 
{ 
    ASSERT(fantasticData); 
    if(!fantasticData) 
     return -1; 
    // ,,, 
    return WOW_VALUE; 
} 

Nhưng cộng đồng TDD có vẻ như để thưởng thức làm một cái gì đó như thế này:

int doMoreWonderfulThings(const int* fantasticData) 
{ 
    if(!fantasticData) 
     return ERROR_VALUE; 
    // ... 
    return AHA_VALUE; 
} 

TEST(TDD_Enjoy) 
{ 
    ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L)); 
    ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo")); 
} 

Chỉ cần với tôi các phương pháp tiếp cận kinh nghiệm đầu tiên cho phép tôi loại bỏ rất nhiều lỗi tinh vi. Nhưng phương pháp tiếp cận TDD là ý tưởng rất thông minh để xử lý các mã cũ.

"Google" - chúng so sánh "PHƯƠNG PHÁP ĐẦU TIÊN" để "Đi bộ trên bờ với áo phao, bơi đại dương mà không có bất kỳ người bảo vệ an toàn nào".

Cái nào tốt hơn? Cái nào làm cho phần mềm mạnh mẽ?

Trả lời

0

Tôi không biết tiểu sử TDD cụ thể mà bạn đang đề cập đến nhưng các mẫu TDD mà tôi đã sử dụng Assert.AreEqual() cho kết quả tích cực hoặc sử dụng cơ chế ExpectedException (ví dụ: thuộc tính trong .NET.) để khai báo lỗi cần được quan sát.

1

Không có lý do gì khiến gói thử nghiệm của bạn không thể bắt được xác nhận như gói thử nghiệm trong doMoreWonderfulThings. Điều này có thể được thực hiện bằng cách nhờ trình xử lý ASSERT của bạn hỗ trợ một cơ chế gọi lại hoặc kiểm tra xác nhận của bạn có chứa khối try/catch.

4

Trong kinh nghiệm (giới hạn) của tôi, tùy chọn đầu tiên khá an toàn hơn một chút. Trong một trường hợp thử nghiệm bạn chỉ kiểm tra đầu vào được xác định trước và so sánh kết quả, điều này hoạt động tốt miễn là mọi trường hợp cạnh có thể đã được kiểm tra. Tùy chọn đầu tiên chỉ kiểm tra mọi đầu vào và do đó kiểm tra các giá trị 'sống', nó lọc ra các lỗi thực sự nhanh chóng, tuy nhiên nó đi kèm với một hình phạt hiệu suất.

Trong Code Complete Steve McConnell biết chúng tôi phương pháp đầu tiên có thể được sử dụng thành công để lọc ra lỗi trong một lỗi xây dựng gỡ lỗi. Trong bản phát hành, bạn có thể lọc ra tất cả các xác nhận (ví dụ với cờ trình biên dịch) để có được hiệu năng bổ sung.

Theo tôi cách tốt nhất là sử dụng cả hai phương pháp:

Phương pháp 1 để bắt các giá trị bất hợp pháp

int doWonderfulThings(const int* fantasticData) 
{ 
    ASSERT(fantasticData); 
    ASSERTNOTEQUAL(0, fantasticData) 

    return WOW_VALUE/fantasticData; 
} 

và phương pháp 2 để kiểm tra cạnh trường hợp của một thuật toán.

int doMoreWonderfulThings(const int fantasticNumber) 
{ 
    int count = 100; 
    for(int i = 0; i < fantasticNumber; ++i) { 
     count += 10 * fantasticNumber; 
    } 
    return count; 
} 

TEST(TDD_Enjoy) 
{ 
    // Test lower edge 
    ASSERT_EQ(0, doMoreWonderfulThings(-1)); 
    ASSERT_EQ(0, doMoreWonderfulThings(0)); 
    ASSERT_EQ(110, doMoreWonderfulThings(1)); 

    //Test some random values 
    ASSERT_EQ(350, doMoreWonderfulThings(5)); 
    ASSERT_EQ(2350, doMoreWonderfulThings(15)); 
    ASSERT_EQ(225100, doMoreWonderfulThings(150)); 
} 
2

Cả hai cơ chế đều có giá trị. Bất kỳ khung kiểm thử hợp lệ nào cũng sẽ bắt được lời khẳng định chuẩn(), vì vậy chạy thử nghiệm khiến cho khẳng định thất bại sẽ dẫn đến một thử nghiệm không thành công.

Tôi thường có một loạt các lời khẳng định ở đầu mỗi phương pháp C++ với chú thích '// điều kiện tiên quyết'; nó chỉ là một kiểm tra sanity về trạng thái mà tôi mong đợi đối tượng có khi phương pháp được gọi. Chúng thích hợp với bất kỳ khung công tác TDD nào vì chúng không chỉ hoạt động trong thời gian chạy khi bạn đang thử nghiệm chức năng mà còn hoạt động ở thời gian thử nghiệm.

0

Trong C++, tôi thích phương pháp 2 khi sử dụng hầu hết các khuôn khổ thử nghiệm. Nó thường làm cho dễ dàng hơn để hiểu báo cáo thất bại. Điều này là vô giá khi một tháng thử nghiệm đến nhiều năm sau khi thử nghiệm được viết.

Lý do của tôi là hầu hết các khung kiểm tra C++ sẽ in ra tệp và số dòng nơi xác nhận xảy ra mà không có bất kỳ loại thông tin theo dõi ngăn xếp nào.Vì vậy, hầu hết thời gian bạn sẽ nhận được số dòng báo cáo bên trong của hàm hoặc phương thức chứ không phải bên trong trường hợp thử nghiệm.

Ngay cả khi khẳng định được bắt và xác nhận lại từ người gọi, dòng báo cáo sẽ có câu lệnh khai thác và có thể không ở bất kỳ đâu gần đường trường hợp được gọi là phương thức hoặc chức năng được xác nhận. Điều này có thể thực sự gây phiền nhiễu khi hàm được xác nhận có thể đã được sử dụng nhiều lần trong trường hợp kiểm tra.

Có ngoại lệ. Ví dụ: khung kiểm tra của Google có một tuyên bố theo dõi phạm vi sẽ in như một phần của dấu vết nếu một ngoại lệ xảy ra. Vì vậy, bạn có thể kết thúc cuộc gọi đến chức năng kiểm tra tổng quát với phạm vi theo dõi và dễ dàng biết, trong một hoặc hai dòng, dòng nào trong trường hợp kiểm tra chính xác không thành công.