2008-09-29 28 views
61

Tôi đang mở rộng sự hiểu biết Ruby của mình bằng cách mã hóa tương đương với xUnit của Kent Beck trong Ruby. Python (mà Kent viết trong) có một phương thức assert() trong ngôn ngữ được sử dụng rộng rãi. Ruby thì không. Tôi nghĩ rằng nó nên được dễ dàng để thêm này nhưng là hạt nhân đúng nơi để đặt nó?Ruby có phải là thành ngữ để thêm phương thức assert() vào lớp nhân của Ruby không?

BTW, Tôi biết về sự tồn tại của các khung công tác khác nhau trong Ruby - đây là bài tập để tìm hiểu các thành ngữ Ruby, thay vì "hoàn thành công việc".

+3

Tôi thích các vấn đề làm cả hai: dạy bạn và hoàn thành công việc. :) –

Trả lời

77

Không, đó không phải là phương pháp hay nhất. Chức năng tốt nhất để khẳng định() trong Ruby chỉ là nâng

raise "This is wrong" unless expr 

và bạn có thể thực hiện ngoại lệ của riêng bạn nếu bạn muốn cung cấp để xử lý

+22

Bạn cũng có thể sử dụng 'fail if [expr]', nếu bạn thích, điều này sẽ gây ra lỗi Runtime Error. –

+6

'fail' là một bí danh cho' nâng cao', phải không? Cả hai đều cho 'RuntimeError'. (Có thể một người thành ngữ hơn?) –

+0

Xem "không thành công" tại đây: http://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html –

14

Lý do của bạn để thêm phương thức xác nhận vào mô-đun Kernel là gì? Tại sao không chỉ sử dụng một mô-đun khác gọi là Assertions hay gì đó?

Như thế này:

module Assertions 
    def assert(param) 
    # do something with param 
    end 

    # define more assertions here 
end 

Nếu bạn thực sự cần khẳng định của bạn sẽ có sẵn ở khắp mọi nơi làm điều gì đó như thế này:

class Object 
    include Assertions 
end 

Disclaimer: Tôi đã không kiểm tra mã nhưng về nguyên tắc Tôi sẽ làm như thế này

+1

Không phải con khỉ này đang vá sao? Bạn đang thay đổi lớp 'Object'. – tsikov

+0

Vâng, đó là bản vá khỉ cổ điển. Đó là cách để làm điều đó, Nếu bạn thực sự phải làm cho phương thức 'assert' có sẵn trên toàn cầu. Tuy nhiên, tôi sẽ không khuyên bất cứ ai sử dụng khỉ vá như thế này trong các dự án phi đồ chơi. –

4

Hiểu biết của tôi là bạn đang viết bộ thử nghiệm của riêng mình như một cách làm quen với Ruby. Vì vậy, trong khi thử nghiệm :: Đơn vị có thể hữu ích như một hướng dẫn, nó có lẽ không phải là những gì bạn đang tìm kiếm (vì nó đã được thực hiện công việc).

Điều đó nói rằng, xác nhận của python là (đối với tôi, ít nhất), tương tự hơn với C's assert(3). Nó không được thiết kế đặc biệt cho các bài kiểm tra đơn vị, thay vì bắt các trường hợp "điều này sẽ không bao giờ xảy ra".

Cách kiểm tra đơn vị tích hợp của Ruby có xu hướng xem vấn đề, đó là mỗi trường hợp thử nghiệm riêng lẻ là một phân lớp của TestCase và bao gồm câu lệnh xác nhận tính hợp lệ của những gì được truyền cho nó và ghi lại để báo cáo.

6

Đó không phải là đặc biệt thành ngữ ngoại lệ cụ thể hơn, nhưng tôi nghĩ rằng đó là một ý tưởng tốt. Đặc biệt nếu được thực hiện như thế này:

def assert(msg=nil) 
    if DEBUG 
     raise msg || "Assertion failed!" unless yield 
    end 
end 

Bằng cách đó không có tác động nếu bạn quyết định không chạy với DEBUG (hoặc một số công tắc tiện lợi khác, tôi đã sử dụng Kernel.do_assert trong quá khứ) đề ra.

25

Tôi nghĩ rằng nó hoàn toàn hợp lệ để sử dụng các xác nhận trong Ruby. Nhưng bạn đang đề cập đến hai điều khác nhau:

  • xUnit frameworks use assert phương pháp để kiểm tra kỳ vọng kiểm tra của bạn. Chúng được dự định sẽ được sử dụng trong mã thử nghiệm của bạn, chứ không phải trong mã ứng dụng của bạn.
  • Một số ngôn ngữ như C, Java hoặc Python, bao gồm một công trình xây dựng assert nhằm mục đích được sử dụng bên trong mã chương trình của bạn, để kiểm tra các giả định bạn thực hiện về tính toàn vẹn của chúng. Các kiểm tra này được xây dựng bên trong chính mã. Chúng không phải là tiện ích thử nghiệm, mà là một tiện ích phát triển.

Gần đây tôi đã viết solid_assert: a little Ruby library implementing a Ruby assertion utility và cũng a post in my blog explaining its motivation .. Nó cho phép bạn viết các biểu thức dưới dạng:

assert some_string != "some value" 
assert clients.empty?, "Isn't the clients list empty?" 

invariant "Lists with different sizes?" do 
    one_variable = calculate_some_value 
    other_variable = calculate_some_other_value 
    one_variable > other_variable 
end  

Và họ có thể bị ngừng hoạt động để assertinvariant được đánh giá là phát biểu có sản phẩm nào. Điều này cho phép bạn tránh bất kỳ vấn đề hiệu suất trong sản xuất. Nhưng hãy lưu ý rằng The Pragmatic Programmers khuyên bạn nên hủy kích hoạt chúng. Bạn chỉ nên hủy kích hoạt chúng nếu chúng thực sự ảnh hưởng đến hiệu suất.

Liên quan đến câu trả lời nói rằng cách Ruby độc đáo đang sử dụng câu lệnh bình thường raise, tôi nghĩ nó thiếu tính biểu cảm. Một trong những quy tắc vàng của chương trình quyết đoán không sử dụng các xác nhận cho xử lý ngoại lệ thông thường. Chúng là hai thứ hoàn toàn khác nhau. Nếu bạn sử dụng cùng một cú pháp cho hai người trong số họ, tôi nghĩ rằng mã của bạn sẽ tối nghĩa hơn. Và tất nhiên bạn mất khả năng hủy kích hoạt chúng.

Bạn có thể tin rằng việc sử dụng xác nhận là điều tốt vì hai cuốn sách cổ điển phải đọc như The Pragmatic Programmer From Journeyman to MasterCode Complete dành toàn bộ các phần cho chúng và đề xuất sử dụng chúng. Ngoài ra còn có một bài viết hay có tiêu đề Programming with assertions minh họa rất rõ những gì là lập trình quyết đoán và khi nào sử dụng nó (nó dựa trên Java, nhưng các khái niệm áp dụng cho bất kỳ ngôn ngữ nào).

+0

Tôi cũng đề nghị "Viết mã rắn" bởi Steve Maguire, cực kỳ C theo định hướng, nhưng nói về khẳng định, chiến lược thử nghiệm và ý tưởng về xây dựng các chức năng cũng áp dụng cho xây dựng phương pháp. –

+0

Rất ít đá quý - cảm ơn – Yarin

Các vấn đề liên quan