RSpec double/mock print method from call

谁说我不能喝 提交于 2021-01-29 06:43:38

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!