Spec RSpec模型属性设置器

Cim*_*imm 5 ruby setter attributes rspec

我正在使用Sinatra(1.2)和RSpec(2.5),并且想要创建一个具有属性TDD样式的新对象.这是最终结果的样子:

class User
  def initialize(name)
    @name = name
  end
end
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

当我运行RSpec时,我得到"预期:1次,收到0次"错误.知道如何解释RSpec我想分配名称属性吗?

注意:我没有使用Rails,没有使用ActiveRecord或任何东西,只有Ruby.

The*_*heo 12

首先,让我解释为什么你写的规范不起作用:

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

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

显然你的代码只是一个例子,任何有用的东西都会对@name变量做些什么,这就是你应该测试的东西.首先编写一个测试User对象将用于什么,然后编写完成该测试所需的所有实现(但不多).编写一个测试,反映对象在实际生产代码中的使用方式.


Dav*_*sky 5

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

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
Run Code Online (Sandbox Code Playgroud)

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