Ruby on rails RSpec+;DatabaseCleaner帮助--过早发生拆卸

Ruby on rails RSpec+;DatabaseCleaner帮助--过早发生拆卸,ruby-on-rails,ruby,rspec,datamapper,Ruby On Rails,Ruby,Rspec,Datamapper,我对RSpec一直坚持使用基于xUnit的测试框架感到有点迷茫,但我要尝试一下 规范编写方式的嵌套特性让我很头疼,因为我应该在哪里进行数据库设置/拆卸 根据自述文件: 现在我不能使用事务,因为我在我的代码中使用它们,所以我只是坚持截断,但这不应该在这里也不应该在那里 我有这个: RSpec.configure do |config| config.mock_with :rspec config.before(:suite) do DatabaseCleaner.strategy

我对RSpec一直坚持使用基于xUnit的测试框架感到有点迷茫,但我要尝试一下

规范编写方式的嵌套特性让我很头疼,因为我应该在哪里进行数据库设置/拆卸

根据自述文件:

现在我不能使用事务,因为我在我的代码中使用它们,所以我只是坚持截断,但这不应该在这里也不应该在那里

我有这个:

RSpec.configure do |config|
  config.mock_with :rspec

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end
这里的问题是,我在
主题
块中创建的任何装置在我尝试在以下
描述
块中使用时都已消失(从数据库中)

例如(使用机械师创建夹具…但这不相关):


我正在努力解决如何嵌套这些
descripe
subject
以及其他块,所以这可能是我的问题,但基本上这失败了,因为当它试图从数据库中获取用户时,由于(:each)钩子被调用,它已经被删除了,大概在
let

之后,如果要同时使用
subject
let
,您需要了解如何/何时调用它们。在这种情况下,
subject
在由
let
生成的
user
方法之前被调用。问题不是在调用
subject
之前从数据库中删除了对象,而是在该点上甚至没有创建对象

如果您使用
let
方法,它在之前添加一个
钩子,该钩子在示例之前隐式调用
用户
方法(因此在调用
主题
之前)

也就是说,我建议您停止挣扎,使用RSpec已经公开的更简单的API:

describe User do
  it "finds a user with login credentials" do
    user = User.make(:username => "test", :password => "password")
    User.get_by_login_credentials!("test", "password").should eq(user)
  end
end
这对我来说似乎简单多了。

你写道:

这里的问题是,当我尝试在下面的descripe或it块中使用它们时,我在subject或let块中创建的任何装置都已经消失(从数据库中)

没错,就是这样。(您使用的不是通常意义上的Rails固定装置,而是工厂——同样如此,因为Rails固定装置很糟糕。)

每个单独的规范(即每个
it
块)都从原始数据库开始(或应该开始)。否则,您的测试将泄漏状态并失去原子性。因此,您应该在需要的规范中创建所需的每一条记录(或者,正如David所说,在
之前的
块中创建,以减少重复)

至于组织你的规格…以任何有意义的方式去做。通常,整个类将有一个外部
descripe
块,内部
descripe
块用于需要公共设置的相关行为或规范组。每个
descripe
上下文可以在
块之前和之后有自己的
。正如您所期望的那样,它们被嵌套,因此执行顺序类似于

内部
之前
规格
内部

外部


如果您想看到一个包含大量RSpec规范和Cucumber故事的项目(尽管每个都有一些旧版本),请查看。

谢谢,我不了解如何/何时调用这些块,您肯定是对的。我最初只是将上面代码中的外部
descripe
视为一个
Test::Unit::TestCase
子类,而每个
it
都像是xUnit框架中的一个测试方法。然后我开始阅读其他人的说明书,他们正在使用
主题接着是一系列的
it。。。应该
块,这让我确信我做错了。我想我需要把头撞在墙上一段时间,这样才有意义;)很快,如果我需要一个由
descripe
块中的所有测试共享的夹具,那么在哪里最好?只需在(:each)
之前使用
?所有这些其他的方法都让我偏离了正轨!很高兴你的天气开始转晴了。
subject
的初衷是支持像
it{shoulda}
这样的一行程序中的
shoulda
匹配器{shoulda}
。它并不是真的打算出现在规格中。它是有文档记录的、公开的、可用的,但我越是在人们的规范中看到它,我就越觉得它不应该出现在那里,这既是出于美观的原因,也是因为在尝试将它与
let
before
挂钩一起使用时会出现明显的混淆。对于一个普通夹具来说,最好的位置是
before(:each)
hook。这很简单,能揭示意图,而且有效:)你应该看看let!它会自动执行给定的块作为每个示例的前钩子。感谢您的解释,非常感谢。我一开始就明白了。只是一些最初的误解。使用RSpec是一种乐趣!(事实上,我是在14小时前开始回复这个问题的,我不知道当时发生了什么;)。。。我想我在打字时换了标签)。是的,我非常喜欢RSpec。我发现它的语法鼓励您考虑行为,而不是实现。顺便说一句,您应该仍然能够使用事务清理数据库。在大多数数据库中,事务都可以嵌套(MySQL是一个显著的例外——这是另一种糟糕的方式)。
describe User do
  describe "finding with login credentials" do
    let(:user) { User.make(:username => "test", :password => "password") }
    subject { User.get_by_login_credentials!("test", "password") }
    it { should == user }
  end
end
describe User do
  it "finds a user with login credentials" do
    user = User.make(:username => "test", :password => "password")
    User.get_by_login_credentials!("test", "password").should eq(user)
  end
end