【问题标题】:How to test initializer number of arguments in Ruby如何在 Ruby 中测试初始化​​参数的数量
【发布时间】:2019-12-08 13:19:36
【问题描述】:

我需要自动分级一个 Ruby 练习,使用 Rspec 进行测试

这个类是纯 ruby​​ 的,我只需要验证属性(存在性和可访问性)以及在初始化程序中接收到的参数数量

# lib/card.rb
class Card
  attr_reader :number, :suit

  def initialize(number, suit)
    @number = number
    @suit = suit
  end
end

# spec/card_spec.rb
require "spec_helper"
require_relative "../lib/card"

describe Card do
  let(:subject) do
    Card.new(1, "D")
  end

  it { expect(Card).to respond_to(:new).with(4).arguments }
end

➜ rspec spec/card_spec.rb
.

Finished in 0.00431 seconds (files took 0.12135 seconds to load)
1 example, 0 failure

尽管初始化程序接收 2 个参数并且我在测试中指定了 4 个参数,但测试仍在通过

【问题讨论】:

  • 由于某种原因,respond_to 似乎无法与new 方法一起正常工作。但它适用于其他自定义方法。可能是一个错误。
  • it { expect(Card).to respond_to(:new).with(2).arguments } 测试self.new 中的Card 方法,这显然不是我们所需要的。 :-/

标签: ruby oop testing rspec


【解决方案1】:

new 方法的元数为 -1,这意味着参数数量可变,因此规范通过是可以的。

见:https://ruby-doc.org/core-2.6.3/Method.html#method-i-arity

问题是你在测试错误的东西/方法。

【讨论】:

  • Card.method(:new).arity-1 是正确的,就像 Card.method(:initialize).arity。你知道为什么吗?
  • 因为Class#newObject#initialize 都无法提前知道用户将传递多少个参数。请注意,传统上,initialize 在子类中被覆盖以获取正确数量的参数,因此这不是问题。例如。如果您检查由 OP 定义的 initialize 方法而不是 Object 中的默认方法,它显然将具有 2。
  • @JörgWMittag 很奇怪。 Card.method(:initialize).arity 返回 -1。我错过了什么吗?
  • @EricDuminil:我不明白你的问题。那就是您正在查看的Object#initialize,它通常意味着在子类中被覆盖,因此它被定义为具有最大灵活的签名。换句话说,结果正是你所期望的,不是吗?
  • @JörgWMittag:好的,我想我明白了。 Card.instance_method(:initialize).arity 确实是 2。混淆来自Card.new 的定义在Card#initialize 中。
【解决方案2】:

问题是Card.new是在Card.initialize中定义的。

所以:

it { expect(Card).to respond_to(:new).with(2).arguments }

实际上是在尝试测试:

class Card
  def self.new(number, suit)
    ...
  end
end

您可以简单地尝试使用不正确的参数初始化 Card 并检查是否引发了 ArgumentError

class Card
  attr_reader :number, :suit

  def initialize(number, suit)
    @number = number
    @suit = suit
  end
end

describe Card do
  context 'when initialized with incorrect number of arguments' do
    [[], [1], [1, 2, 3], [1, 2, 3, 4]].each do |args|
      it { expect { Card.new(*args) }.to raise_error(ArgumentError) }
    end
  end

  context 'when initialized with correct arguments' do
    it { expect(Card.new(1, 'D')).to be_a(Card) }
  end
end

它输出:

Card
  when initialized with incorrect number of arguments
    should raise ArgumentError
    should raise ArgumentError
    should raise ArgumentError
    should raise ArgumentError
  when initialized with correct arguments
    should be a kind of Card

Finished in 0.01455 seconds (files took 0.64291 seconds to load)
5 examples, 0 failures

不过,可能有更清洁的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    相关资源
    最近更新 更多