2012-12-19 33 views
6

Với một mô hình ActiveRecord điển hình, tôi thường có các cuộc gọi lại before_save phân tích cú pháp đầu vào, ví dụ như lấy số time_string từ người dùng và phân tích cú pháp vào trường time.Rails: làm thế nào để kiểm tra before_save callbacks

Đó cài đặt có thể trông như thế này:

before_save :parse_time 
attr_writer :time_string 

private 
def parse_time 
    time = Chronic.parse(time_string) if time_string 
end 

Tôi hiểu rằng nó được coi là thực hành tốt nhất để làm cho các phương thức callback tin. Tuy nhiên, nếu chúng là riêng tư, thì bạn không thể gọi riêng chúng để kiểm tra chúng một cách riêng biệt.

Vì vậy, đối với những người thử nghiệm Rails dày dạn kinh nghiệm, bạn xử lý thử nghiệm loại điều này như thế nào?

+0

Bạn sử dụng biến 'time' đó ở đâu? là một thuộc tính của đối tượng của bạn? –

+0

Ví dụ trên là loại chế tạo, nhưng có, biến thời gian là một thuộc tính đối tượng. – Andrew

Trả lời

9

Trong Ruby, phương pháp cá nhân vẫn có sẵn thông qua Object#send

Bạn có thể khai thác này cho kiểm tra đơn vị bạn như vậy:

project = Project.new 
project.time_string = '2012/11/19 at Noon' 
assert_equal(project.send(:parse_time), '2012-11-19 12:00:00') 
+0

Thú vị, tôi không nhận ra rằng '# send' đã làm việc theo cách đó. Cảm ơn! – Andrew

3

gì tôi sẽ làm là lưu trạng thái của một thể hiện new hoặc build đối tượng của bạn, lưu đối tượng và xác nhận hoặc kỳ vọng dựa trên giá trị của thuộc tính đã được thay đổi bởi before_save

post = Post.new 
post.time_string = '2012/11/19' 
expected_time = Chronic.parse(post.time_string) 
post.save 
assert_equal(post.time, expected_time) 

Bằng cách đó bạn đang kiểm tra hành vi của cách đối tượng nên hành động và không nhất thiết phải thực hiện phương pháp.

+2

Ok, nhưng có hai nhược điểm chính cho điều này: (1) nó chậm. (2) '# save' chạy tất cả các cuộc gọi lại, và nếu một lỗi gọi lại khác ngoài kiểm tra cho điều này cũng sẽ thất bại, mặc dù nó có thể đang hoạt động. – Andrew

+0

Tôi cũng thích cách này, vì nó không quan trọng cách thức hoạt động của internals, miễn là trạng thái kết thúc là đúng, nhưng có những ưu điểm (tốc độ, độ phủ sóng, hiểu biết) để kiểm tra các phương thức trực tiếp. – Unixmonkey

+0

Re: thử nghiệm hành vi so với thực hiện, tôi hiểu những gì bạn có nghĩa là, nhưng mục tiêu ở đây là để kiểm tra hành vi của phương pháp trong sự cô lập hơn là một bài kiểm tra tích hợp bao gồm nhiều hành vi. Phương pháp thử nghiệm riêng lẻ không có nghĩa là bạn nhất thiết phải thử nghiệm triển khai thay vì hành vi. – Andrew

0

Có những lúc tôi có điều kiện if trên các cuộc gọi lại trong trường hợp này tôi sử dụng run_callbacks.

before_save :parse_time, :if => Proc.new{ |post| post.foo == 'bar' } 

được kiểm tra một cách tích cực bởi

post = Post.new 
post.foo = 'bar' 
expected_time = Chronic.parse(post.time_string) 
post.run_callbacks :before_save 
assert_equal(post.time, expected_time) 

và tiêu cực bởi

post = Post.new 
post.foo = 'wha?' 
post.run_callbacks :before_save 
assert_nil(post.time) 

Xem the APIa blog để biết thêm chi tiết.

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