2008-11-06 18 views
15

Tôi sử dụng khung kiểm tra Tăng cường để kiểm tra đơn vị mã C++ của tôi và tự hỏi liệu có thể kiểm tra xem một hàm sẽ xác nhận không? Có, nghe có vẻ hơi lạ nhưng chịu với tôi! Nhiều hàm của tôi kiểm tra các tham số đầu vào khi nhập, xác nhận nếu chúng không hợp lệ và sẽ hữu ích khi kiểm tra điều này. Ví dụ:Kiểm tra để khẳng định trong khung kiểm tra Tăng cường

void MyFunction(int param) 
{ 
    assert(param > 0); // param cannot be less than 1 
    ... 
} 

Tôi muốn để có thể làm điều gì đó như thế này:

BOOST_CHECK_ASSERT(MyFunction(0), true); 
BOOST_CHECK_ASSERT(MyFunction(-1), true); 
BOOST_CHECK_ASSERT(MyFunction(1), false); 
... 

Bạn có thể kiểm tra các trường hợp ngoại lệ được ném sử dụng Boost thử nghiệm vì vậy tôi tự hỏi nếu có một số khẳng định diệu quá. ..

+0

Tôi biết đây là chủ đề cũ nhưng tôi đã thêm giải pháp mà tôi đã đưa ra để giúp tôi làm việc. – grokus

Trả lời

5

Tôi không nghĩ vậy. Bạn luôn có thể viết khẳng định của riêng bạn mà ném một ngoại lệ và sau đó sử dụng BOOST_CHECK_NOTHROW() cho ngoại lệ đó.

0

Xin lỗi, nhưng bạn đang tấn công vấn đề của mình một cách sai lầm.

"khẳng định" là sinh sản của ma quỷ (a.k.a. "C") và vô dụng với bất kỳ ngôn ngữ nào có ngoại lệ thích hợp. Đó là waaaaaay tốt hơn để reimplement một chức năng khẳng định giống như với ngoại lệ. Bằng cách này bạn thực sự có cơ hội xử lý các lỗi đúng cách (bao gồm các thủ tục dọn dẹp thích hợp) hoặc kích hoạt chúng theo ý muốn (để kiểm tra đơn vị).

Bên cạnh đó, nếu mã của bạn đã từng chạy trong Windows, khi bạn không xác nhận, bạn sẽ nhận được một cửa sổ bật lên vô dụng cung cấp cho bạn để gỡ lỗi/hủy/thử lại. Tốt cho các bài kiểm tra đơn vị tự động.

Vì vậy, hãy tự ưu tiên và viết lại chức năng khẳng định để ném ngoại lệ. Có một ở đây: How can I assert() without using abort()?

Bỏ nó vào macro để bạn có được _ _FILE _ _ và _ _ LINE _ _ (hữu ích để gỡ lỗi) và bạn đã hoàn tất.

+12

Nếu bạn tin rằng điều này bạn đang sử dụng khẳng định sai cách. Các xác nhận chỉ nên được sử dụng cho những thứ phải đúng hoặc đó là lỗi * lập trình viên *, xem ví dụ được đưa ra trong câu hỏi. Nếu một lập trình viên sử dụng một hàm sai cách bạn muốn biết rằng càng sớm càng tốt. –

+1

Tôi đồng ý với Andreas. Các xác nhận và nơi các static_asserts có thể không được thay thế bằng các ngoại lệ. Chúng có nghĩa là để phát hiện lỗi của các lập trình viên. –

+4

Và bạn làm gì trong trường hợp lỗi lập trình ???? Tai nạn và thất bại khó ??? Hãy nghiêm túc, mọi người. Asserts là lỗi thời, thời gian. Không có lý do gì để sử dụng chúng trong mã hiện đại. Và bạn "muốn biết càng sớm càng tốt" sau đó chỉ cần ngừng làm "bắt (...)". – rlerallut

9

Có hai loại lỗi mà tôi muốn kiểm tra: các lỗi bất biến và lỗi thời gian chạy.

Các bất biến là những thứ luôn luôn đúng, bất kể là gì. Đối với những người, tôi sử dụng khẳng định. Những thứ như bạn không nên đi qua cho tôi một con trỏ không cho bộ đệm đầu ra bạn đang cho tôi. Đó là một lỗi trong mã, đơn giản và đơn giản. Trong bản dựng gỡ lỗi, nó sẽ xác nhận và cho tôi cơ hội sửa nó. Trong một xây dựng bán lẻ, nó sẽ gây ra một sự vi phạm truy cập và tạo ra một minidump (Windows, ít nhất là trong mã của tôi) hoặc một coredump (Mac/unix). Không có catch mà tôi có thể làm điều đó có ý nghĩa để đối phó với dereferencing một con trỏ bằng không. Trên Windows catch (...) có thể ngăn chặn vi phạm truy cập và cung cấp cho người dùng một cảm giác sai lầm về sự tự tin rằng mọi thứ đều ổn khi họ đã trải qua khủng khiếp, khủng khiếp sai. Đây là một trong những lý do tại sao tôi đã tin rằng catch (...) nói chung là một mùi mã trong C + + và nơi duy nhất hợp lý mà tôi có thể nghĩ rằng hiện diện là trong main (hoặc WinMain) ngay trước khi bạn tạo ra một lõi đổ và lịch sự thoát khỏi ứng dụng.

Lỗi thời gian chạy là những thứ như "Tôi không thể ghi tệp này do quyền" hoặc "Tôi không thể ghi tệp này vì đĩa đã đầy". Đối với các loại lỗi này, việc loại bỏ một ngoại lệ có ý nghĩa bởi vì người dùng có thể thực hiện điều gì đó giống như thay đổi quyền trên thư mục, xóa một số tệp hoặc chọn một vị trí thay thế để lưu tệp. Các lỗi thời gian chạy này có thể được người dùng điều chỉnh. Vi phạm một sự bất biến không thể được sửa bởi người dùng, chỉ bởi một lập trình viên. (Đôi khi cả hai đều giống nhau, nhưng thường thì không.)

Kiểm tra đơn vị của bạn sẽ buộc mã phải ném ngoại lệ lỗi thời gian chạy mà mã của bạn có thể tạo. Bạn cũng có thể muốn ép buộc ngoại lệ từ cộng tác viên của mình để đảm bảo rằng hệ thống của bạn đang được kiểm tra là ngoại lệ an toàn.

Tuy nhiên, tôi không tin rằng có giá trị trong việc cố gắng buộc mã của bạn phải khẳng định chống lại các bất biến với các bài kiểm tra đơn vị.

3

Tôi nghĩ câu hỏi này và một số câu trả lời, gây nhầm lẫn phát hiện lỗi thời gian chạy với phát hiện lỗi. Họ cũng gây nhầm lẫn ý định và cơ chế.

Lỗi thời gian chạy là điều có thể xảy ra trong chương trình chính xác 100%. Nó cần phát hiện, và nó cần báo cáo và xử lý thích hợp, và nó cần được kiểm tra. Lỗi cũng xảy ra, và để thuận tiện cho lập trình viên, tốt hơn là bắt chúng sớm bằng cách sử dụng kiểm tra điều kiện tiên quyết hoặc kiểm tra bất biến hoặc xác nhận ngẫu nhiên. Nhưng đây là công cụ của lập trình viên. Thông báo lỗi sẽ không có ý nghĩa đối với người dùng thông thường và dường như không hợp lý để kiểm tra hành vi chức năng trên dữ liệu mà chương trình được viết đúng cách sẽ không bao giờ chuyển đến nó.

Vì mục đích và cơ chế, cần lưu ý rằng ngoại lệ không có gì là ma thuật. Một số thời gian trước đây, Peter Dimov cho biết trên danh sách gửi thư Boost (khoảng) rằng "ngoại lệ chỉ là cơ chế nhảy phi địa phương". Và điều này rất đúng. Nếu bạn có ứng dụng mà nó có thể tiếp tục sau khi một số lỗi nội bộ, mà không có nguy cơ rằng một cái gì đó sẽ bị hỏng trước khi sửa chữa, bạn có thể thực hiện tùy chỉnh khẳng định rằng ném ngoại lệ C++. Nhưng nó sẽ không thay đổi ý định, và sẽ không làm thử nghiệm cho những lời khẳng định hợp lý hơn nhiều.

12

Có cùng một vấn đề, tôi đã đào qua tài liệu (và mã) và tìm thấy "giải pháp".

Boost UTF sử dụng boost::execution_monitor (trong <boost/test/execution_monitor.hpp>). Điều này được thiết kế với mục đích bắt giữ mọi thứ có thể xảy ra trong quá trình thực hiện kiểm tra. Khi xác nhận được tìm thấy execution_monitor chặn nó và ném boost::execution_exception. Do đó, bằng cách sử dụng BOOST_REQUIRE_THROW bạn có thể khẳng định sự thất bại của một khẳng định.

vậy:

#include <boost/test/unit_test.hpp> 
#include <boost/test/execution_monitor.hpp> // for execution_exception 

BOOST_AUTO_TEST_CASE(case_1) 
{ 
    BOOST_REQUIRE_THROW(function_w_failing_assert(), 
         boost::execution_exception); 
} 

Nên làm các trick. (Nó làm việc cho tôi.)

Tuy nhiên (hoặc từ chối về quyền):

  • Nó làm việc cho tôi. Tức là, trên Windows XP, MSVC 7.1, tăng 1.41.0. Có thể không phù hợp hoặc bị hỏng trên thiết lập của bạn.

  • Nó có thể không phải là ý định của tác giả của Kiểm tra tăng cường. (mặc dù nó có vẻ là mục đích của execution_monitor).

  • Nó sẽ xử lý mọi dạng lỗi nghiêm trọng theo cùng một cách. Tôi e nó có thể là rằng một cái gì đó khác với khẳng định của bạn là không. Trong trường hợp này, bạn có thể bỏ sót e g một lỗi tham nhũng bộ nhớ, và/hoặc bỏ lỡ một khẳng định thất bại không thành công.

  • Nó có thể phá vỡ các phiên bản tăng cường trong tương lai.

  • Tôi hy vọng nó sẽ thất bại nếu chạy trong Cấu hình bản phát hành, vì khẳng định sẽ bị tắt và mã mà khẳng định được đặt để ngăn sẽ chạy. Kết quả trong hành vi rất không xác định.

  • Nếu, trong Cấu hình bản phát hành cho msvc, một số lỗi khẳng định hoặc lỗi nghiêm trọng khác sẽ xảy ra dù sao nó sẽ không bị phát hiện. (xem tài liệu execute_monitor).

  • Nếu bạn sử dụng khẳng định hay không là tùy thuộc vào bạn. Tôi thích họ.

Xem:

Ngoài ra, nhờ vào Gennadiy Rozental (Tác giả của Boost Test), nếu bạn tình cờ đọc, Great làm việc !!

+0

Không hoạt động với tôi - debian gcc 4.4.6 – sje397

+0

cũng không dành cho tôi ubuntu 14.04, tăng 1.55, gcc 4.8.2 – RichardBruce

+0

không hoạt động với tôi gcc 4.8.1 centOs 2.6.x – bjackfly

2

Ở nơi làm việc, tôi đã gặp phải vấn đề tương tự. Giải pháp của tôi là sử dụng cờ biên dịch. Khi lá cờ của tôi GROKUS_TESTABLE trên GROKUS_ASSERT của tôi bị biến thành một ngoại lệ và với Boost, bạn có thể kiểm tra các đường dẫn mã mà ném các ngoại lệ. Khi GROKUS_TESTABLE bị tắt, GROKUS_ASSERT được dịch sang C++ assert().

#if GROKUS_TESTABLE 
#define GROKUS_ASSERT ... // exception 
#define GROKUS_CHECK_THROW BOOST_CHECK_THROW 
#else 
#define GROKUS_ASSERT ... // assert 
#define GROKUS_CHECK_THROW(statement, exception) {} // no-op 
#endif 

động lực ban đầu của tôi là để hỗ trợ gỡ lỗi, ví dụ: assert() có thể được sửa lỗi một cách nhanh chóng và các ngoại lệ thường là khó khăn hơn để gỡ lỗi trong gdb. Cờ biên dịch của tôi dường như cân bằng khả năng debuggability và testability khá tốt.

Hy vọng điều này sẽ giúp