【问题标题】:How to write an rspec for do-end block and check method is called or not using stub/mock如何为 do-end 块编写 rspec 并使用存根/模拟调用或不调用检查方法
【发布时间】:2021-07-05 04:25:06
【问题描述】:

所有单元测试用例都应该被模拟/存根。用于检查错误方法和结果方法的 Rspec。

require 'yaml'
require_relative 'checkerror'

class Operations
  def initialize
      @path
      @checks_to_run
      @check
  end

  # This will prints the result of each file offences or no offences
  def result (result_log: File.new('result.txt', 'a+'))
    # @check.errors should be stubbed with a value to enter in if or else block
    if @check.errors.empty?
      # Output is printing in both console as well as file
      result_log.write("#{@check.checker.file_path} :: No offensenses detected\n")
      puts "#{@check.checker.file_path} :: No offensenses detected\n"
    else
      @check.errors.uniq.each do |err|
        puts "#{@check.checker.file_path} : #{err}\n"
        result_log.write("#{@check.checker.file_path} : #{err}\n")
      end
    end
    result_log.close
  end

  def rules_to_run
    @checks_to_run = YAML.load(File.read('lib/property.yaml'))
  end

  def path_of_directory
    @path = gets.chomp
  end

  def checkerror
    Dir[File.join(@path, '**/*.rb')].each do |file|
      @check = CheckError.new(file)
      @check.check_alphabetized_constants if @checks_to_run.include?('check_alphabetized_constants')
      @check.check_empty_line_before_return if @checks_to_run.include?('check_empty_line_before_return')
      #result is called to print errors
      result
    end
  end
end

我已经为 checkerror 方法编写了 rspec

context '#checkerror' do
  it 'only check the method is called or not' do
    allow(@check_to_run).to receive(:include?).and_return(true)
    allow(@check).to receive(:check_alphabetized_contants)
    operation = Operation.new
    operation.checkerror
    expect(@check).to have_received(:check_alphabetized_constants)
  end
end

但出现错误

TypeError: no implicit conversion of nil into string.

我认为还没有进入 do-end 块的循环,并且我猜存根在语法上也是错误的。

【问题讨论】:

  • 请编辑您的问题以添加完整的堆栈跟踪和任何允许重现您的错误的 rspec 初始化程序。
  • 这是一个非常令人沮丧的问题,因为当底层代码实际上没有意义时,您正在为 rspec 实现寻求非常具体的帮助。正如我之前提到的那样,您实际上并未将 @path@check_to_run 变量设置为任何内容,因此此代码实际上无效;你希望Dir[File.join(nil, '**/*.rb')].each .... 做什么?!
  • 换句话说,你不能这样做:operation = Operation.new。您的 Operation 类至少期望使用 pathchecks_to_run 进行初始化。我将尝试在答案中为您重写此内容,但您确实需要退后一步并编写一个有效的实现,然后再进行单元测试。
  • 当然。我会做的

标签: ruby rspec


【解决方案1】:

下面是对您的代码进行的相当最小的更改,以便更有意义并且可以实际进行测试:

require 'yaml'
require_relative 'checkerror'

class Operations
  def initialize(path: path_of_directory, checks_to_run: rules_to_run):                   
    @path = path      
    @checks_to_run = checks_to_run
  end                 
                      
  def log_result(file, errors, result_log: File.new('result.txt', 'a+'))
    if errors.empty?
      # Output is printing in both console as well as file
      result_log.write("#{file} :: No offensenses detected\n")
      puts "#{file} :: No offensenses detected\n"
    else                              
      errors.uniq.each do |err|
        puts "#{file} : #{err}\n"
        result_log.write("#{file} : #{err}\n")
      end                             
    end                               
    result_log.close                  
  end                                 
                                      
  def checkerror                      
    Dir[File.join(@path, '**/*.rb')].each do |file|
      checker = CheckError.new(file)
      checker.check_alphabetized_constants if @checks_to_run.include?('check_alphabetized_constants')
      checker.check_empty_line_before_return if @checks_to_run.include?('check_empty_line_before_return')
      log_result(file, checker.errors)
    end         
  end           
                
  # These methods feel very out-of-place!! It would be advisiable to move these outside of this class...
  def rules_to_run
    @checks_to_run = YAML.load(File.read('lib/property.yaml'))
  end           
                
  def path_of_directory
    @path = gets.chomp
  end           
end

重点说明:

  • 您实际上需要设置实例变量。例如,在您之前的实现中,@pathnil - 所以这没有任何意义。
  • @checks_to_run 这样的存根变量(顺便说一句,你拼错了!)不是一个好主意。为什么不首先将变量设置为所需的值?
  • 你不能存根甚至没有初始化的变量,比如@check——这不是存根的工作方式。存根不像是“远距离的诡异动作”,它会修改代码的实际行为方式;这是关于设置依赖项的响应行为。

话虽如此...您的测试现在大致如下所示:

describe '#checkerror' do
  let(:path) { Dir.mktmpdir('my-temporary-directory') }
  let!(:rb_file_in_path) { Tempfile.new('test-file.rb', tmpdir) }
  let(:mock_checker) { instance_double(CheckError) }

  it 'calls check_alphabetized_contants when this is a check to run' do
    allow(CheckError).to receive(:new).and_return(mock_checker)
    allow(mock_checker).to receive(:check_alphabetized_constants)

    operation = Operation.new(path: path, checks_to_run: ['check_alphabetized_constants'])
    operation.checkerror

    expect(mock_checker).to have_received(:check_alphabetized_constants)
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-19
    • 2014-05-22
    • 2013-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    相关资源
    最近更新 更多