【问题标题】:Spec RSpec model attribute setterSpec RSpec 模型属性设置器
【发布时间】:2012-07-20 21:26:27
【问题描述】:

我正在使用 Sinatra (1.2) 和 RSpec (2.5),并希望创建一个具有属性 TDD 样式的新对象。最终结果应该是这样的:

class User
  def initialize(name)
    @name = name
  end
end

我知道我必须在实施之前编写示例,但我想在这里解释我的问题。 :) 这是到目前为止我没有工作的规范:

describe User
  it "creates a new user object" do
    name = mock("A name")
    user = mock(User) # shouldn't do this, see the reply's
    user.should_receive(:name=).with(name)
    User.new(name)
  end
end

当我运行 RSpec 时,我收到“预期:1 次,收到 0 次”错误。知道如何解释我想分配 name 属性的 RSpec 吗?

注意:我没有使用 Rails,也没有使用 ActiveRecord 或其他任何东西,只是使用 Ruby。

【问题讨论】:

  • 供将来参考:模拟用户对象不是一个好主意,我的错。谢谢大家的意见。

标签: ruby attributes rspec setter


【解决方案1】:

首先,让我解释一下为什么您编写的规范不起作用:

您设置了一个期望,即mock(User) 返回的模拟对象应该收到name=。这有两个问题。首先,模拟不会收到任何东西,因为它永远不会被调用。 mock(User) 返回一个模拟对象,它不能用于设置对 User 类对象将接收什么的期望(只需执行 User.should_receive(...))。其次,即使您对User 类对象设置了期望值,该对象也永远不会收到name=。这也有两个原因:首先因为name=(如果它存在)将是一个实例方法,因此不会在类对象上调用,其次,您声明没有name= 实例方法。您的代码所做的是它设置了一个实例变量。

现在,您应该如何为此编写测试?你不应该。测试是定义和断言行为,而不是实现。设置实例变量是纯粹的实现。在您的示例代码中无法从类外部获取 @name 实例变量的值,因此没有理由为它编写测试。

显然您的代码只是一个示例,任何有用的东西都可以对@name 变量做一些事情,这就是您应该测试的内容。首先为 User 对象的用途编写测试,然后编写完成该测试所需的所有实现(但仅此而已)。编写一个测试来反映该对象将如何在实际生产代码中使用。

【讨论】:

  • 谢谢西奥。用户模拟确实是非常错误的,我不应该那样做。你说的和大卫一样,我不应该测试实现,而是保持在更高的水平并测试行为。
【解决方案2】:

我真的建议您不要使用模拟来解决这个问题。这不是他们的目的。事实上,像这样指定 getter/setter 并不是 TDD 的真正用途。这个想法是让需求驱动 setter/getter 存在。例如,可能要求用户的姓名在他/她登录时出现在欢迎消息中。然后您可以执行以下操作:

describe 'login process' do
  it "displays user's name after successful login" do
    user = User.new("Cimm", "cimm@somewhere.com", "secret")
    post "/login", :email => "cimm@somewhere.com", :password => "secret"
    last_response.body.should =~ /Welcome Cimm/m
  end
end

这指定了行为,并强制您实现设置 name 属性的方法(在本例中是通过构造函数)和访问它的方法。无需直接指定构造函数。

【讨论】:

  • 感谢大卫,无法与您争论解决此问题的最佳方法。 ;) 我明白你的意思,是的,你是对的,我在这里跳过了几个步骤,应该先回到更高的级别。还有一些我不是很喘不过气来......在某个时候我将再次处于模型级别,我将不得不创建 User.new 方法,我是否跳过属性分配,因为它已经过测试视图规范?
【解决方案3】:

你真的想模拟你正在开发的对象吗?

require 'rspec'

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end 
end

describe User do
  subject {User.new "other name"}

  it "creates a new user object" do
    subject.should respond_to :name=
  end 
end

【讨论】:

  • 即使这让我觉得规范太具有侵略性了。请参阅我的其他评论。
  • 谢谢韦斯,这将是对我问题的简单回答。阅读大卫的回复,我想我看到了我的错误,应该以不同的方式处理这个问题。顺便说一句,您对模拟的 User 类是正确的,不应该这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多