2013-07-17 32 views
17

Tôi muốn làm là chạy ruby sayhello.rb trên dòng lệnh, sau đó nhận Hello from Rspec.Cách kiểm tra đặt trong rspec

Tôi đã có mà với điều này:

class Hello 
    def speak 
    puts 'Hello from RSpec' 
    end 
end 

hi = Hello.new #brings my object into existence 
hi.speak 

Bây giờ tôi muốn viết một bài kiểm tra trong rspec để kiểm tra xem các đầu ra dòng lệnh là trong thực tế "Hello từ RSpec" và không phải là "Tôi thích Unix "

KHÔNG LÀM VIỆC. Tôi hiện có điều này trong tệp sayhello_spec.rb của mình

require_relative 'sayhello.rb' #points to file so I can 'see' it 

describe "sayhello.rb" do 
    it "should say 'Hello from Rspec' when ran" do   
    STDOUT.should_receive(:puts).with('Hello from RSpec')  
    end 
end 

Ngoài ra, tôi cần thực sự xem thử nghiệm sẽ trông như thế nào trong RSPEC của tôi.

Trả lời

13

Bạn đang thực thi mã của mình trước khi nhập khối thử nghiệm, do đó, các kỳ vọng không được đáp ứng. Bạn cần phải chạy mã trong khối kiểm tra sau khi thiết lập những kỳ vọng (ví dụ như bằng cách di chuyển các báo cáo require_relative sau khi tuyên bố STDOUT....), như sau:

describe "sayhello.rb" do 
    it "should say 'Hello from Rspec' when ran" do   
    STDOUT.should_receive(:puts).with('Hello from RSpec') 
    require_relative 'sayhello.rb' #load/run the file 
    end 
end 
+0

Làm cách nào để biết về mã trong 'sayhello.rb'? – bswinnerton

+1

RSpec không cần biết (ví dụ: truy cập) mã trong 'sayhello.rb'. Spec chỉ đơn giản là đặt một kỳ vọng vào 'STDOUT.puts' được xây dựng trong Ruby. Kỳ vọng được đáp ứng sau khi 'sayhello.rb' được tải và chạy (tức là' require'd). –

+5

Đây là cùng một kỳ vọng với cú pháp RSpec mới: 'mong đợi (STDOUT) .để nhận (: đặt) .với (" Xin chào từ RSpec ")' – Jankeesvw

11

Bạn có thể giải quyết việc này bằng active_support thư viện Rails', có thêm một capture phương pháp:

require 'active_support/core_ext/kernel/reporting' 
require_relative 'sayhello' 

describe Hello do 
    it "says 'Hello from RSpec' when ran" do 
    output = capture(:stdout) do 
     hi = Hello.new 
     hi.speak 
    end 
    expect(output).to include 'Hello from RSpec' 
    end 
end 
+10

'# capture' không được dùng nữa và sẽ bị xóa trong Rails 5. https://github.com/rails/rails/blob/dd7bd8c023696657a600ee5dba16bfe5def876bf/activesupport/lib/active_support/core_ext/kernel/reporting.rb#L91 – barelyknown

9

Dựa trên câu trả lời/bình luận trước đó, một giải pháp sử dụng cú pháp mới mà không cần một viên ngọc sẽ trông như thế này:

describe "sayhello.rb" do 
    it "should say 'Hello from Rspec' when run" do   
    expect(STDOUT).to receive(:puts).with('Hello from RSpec') 
    require_relative 'sayhello.rb' # load/run the file 
    end 
end 
3

Hơi giống với câu trả lời của bswinnerton, người ta có thể thu được đầu ra puts và sau đó thử nghiệm với đầu ra đã thu, mà không phải sử dụng phương pháp capture phụ thuộc vào thư viện (mà ai đó đã đề cập không được chấp nhận trong Rails 5).

Ruby có biến toàn cầu có tên $stdout theo mặc định được điền bởi hằng số STDOUT. STDOUT là dữ liệu gửi dữ liệu đến luồng xuất bản của quá trình ruby ​​(không chắc chắn liệu "luồng" có phải là cụm từ phù hợp tại đây hay không). Về cơ bản trong một trường hợp ngây thơ STDOUT.puts("foo") sẽ dẫn đến "foo \ n" xuất hiện trong cửa sổ đầu cuối của bạn. $stdout.puts("foo") sẽ thực hiện tương tự vì tên biến số $stdout đề cập đến STDOUTtrừ khi bạn gán lại nó (điểm chính tại đây). Cuối cùng puts("foo") là cú pháp đường cho $stdout.puts("foo").

Chiến lược sau đó sẽ gán lại $stdout cho một phiên bản IO cục bộ mà bạn có thể kiểm tra sau khi chạy mã của mình để xem "Hello from RSpec" có hiển thị trong nội dung của nó không.

Làm thế nào điều này sẽ làm việc:

describe "sayhello.rb" do 
    it "should say 'Hello from Rspec' when ran" do   
    $stdout = StringIO.new 

    # run the code 
    # (a little funky; would prefer Hello.new.speak here but only changing one thing at a time) 
    require_relative 'sayhello.rb' 

    $stdout.rewind # IOs act like a tape so we gotta rewind before we play it back 

    expect($stdout.gets.strip).to eq('Hello from Rspec') 
    end 
end 
+0

Phương pháp này có thể được sử dụng để kiểm tra nhiều thông điệp xuất bản không? (so với các câu trả lời khác để kiểm tra một) –

+2

@matrim_c: Tôi biết đã muộn cho bạn nhưng trả lời câu hỏi này cho bất kỳ ai khác đến đây. Có, bạn có thể sử dụng điều này để kiểm tra nhiều thông điệp xuất bản. Đối tượng StringIO hoạt động như một tệp, với nhiều dòng. 'get' là một lệnh để đọc một dòng đơn (bao gồm ký tự dòng mới' \ n'), sau đó di chuyển đầu đọc đến ký tự đầu tiên của dòng tiếp theo. Gọi 'gets' nhiều lần sẽ tạo ra các dòng theo thứ tự chúng được thêm vào với' puts'. Việc gọi 'read' trên StringIO sẽ cho bạn toàn bộ nội dung, bao gồm các ký tự' \ n' giữa các dòng. –

7

Tôi nghĩ rằng cách tốt nhất là sử dụng rspec xây dựng sản lượng khớp https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher

dụ Fore, đây là lớp học của bạn

class MakeIt 
    def awesome(text) 
    puts "Awesome #{text}" 
    end 
end 

và thử nghiệm của bạn

describe MakeIt do 
    describe '#awesome' do 
    it 'prints awesome things' do 
     expect do 
     MakeIt.new.awesome('tests') 
     end.to output('Awesome tests').to_stdout 
    end 

    it 'does not print not awesome things' do 
     expect do 
     MakeIt.new.awesome('tests') 
     end.to_not output('Not awesome tests').to_stdout 
    end 
    end 
end 

Đẹp, sạch sẽ và theo sách!

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