问题
My method prints in the console a list of viewed TV Shows. I want to test call method which trigger private print_result
method:
def initialize(parser)
@parser = parser
@views_hash = parser.page_views
end
def call
puts "\n"
puts 'LIST OF MOST POPULAR TV SHOWS'
print_results(sort_all)
puts "\n\n"
end
private
def print_results(sorted_hash)
puts "\n"
puts "#{'TV Show'.center(20)} | VIEWS"
puts '---------------------+----------'
sorted_hash.each do |page, views_no|
puts "#{page.ljust(20)} | #{views_no}"
end
end
Specs:
describe '#call' do
before do
double(print_results: expected_print)
subject.call
end
let(:expected_print) do
" TV Show | VIEWS
---------------------+----------
/that_70s_show | 1"
end
it 'print results' do
expect do
subject.views_hash.send(:print_results)
end.to output(expected_print).to_stdout
end
end
How to mock this print_results
because right now it shows me
NoMethodError: undefined method
print_results` and returns printed table at the same time.
回答1:
Extract Testable Methods; Don't Mock Standard Output
What you're asking to do seems like an anti-pattern. You should never test core Ruby functions like #puts in your specs unless you are doing something really unusual. Even then, you're likely testing the wrong thing in your current spec.
Instead, you should be validating that sorted_hash contains your expected values, or that your formatted output string conforms to some known value. If you really want to test the output of your #print_results method, then you should refactor it into a more test-friendly set of methods.
At a very high level, you should be doing something like:
def generate_results sorted_hash
results = []
sorted_hash.each do |page, views_no|
results.append "#{page.ljust(20)} | #{views_no}"
end
results
end
def formatted_output sorted_hash
str = <<~EOF
#{'TV Show'.center(20)} | VIEWS
---------------------+----------
EOF
str << generate_results(sorted_hash)
end
def print_results sorted_hash
puts formatted_output
end
This isn't tested code, but it should give you the general idea. The notion is that each method does one simple thing where you can inspect the return value to ensure it's what you are expecting, rather than trying to mock a basic thing like standard output that should "just work." The refactored methods should be individually testable, while the new #print_results just sends stuff to standard output and doesn't really need a test unless you have monkeypatched Kernel#puts or redefined standard output.
来源:https://stackoverflow.com/questions/65135207/rspec-double-mock-print-method-from-call