【问题标题】:Rspec and rails problemRspec和rails问题
【发布时间】:2011-07-28 09:11:34
【问题描述】:

我对 rspec 和 rails 有一些奇怪的问题。所以我有模型测试:

require 'spec_helper'

describe User do
  before(:each) do
    @attr = { name: "johnkowalski", fullname: "John Kowalski", 
      email: "kowalski@example.com", password: "foobar" }
  end

  describe "Create a user" do

    it "test1" do
      User.create!(@attr)
    end

    it "test2" do
      User.create!(@attr)
    end

    it "test3" do
      User.create!(@attr)
      @p = { name: "testowy", fullname: "John Kowalski", 
      email: "kowalski@example.com", password: "foobar" }
      a = User.new(@p)
      a.should_not be_valid
    end

    it "test4" do
      User.create!(@attr)
    end
  end
end

它通过没有问题,但是当我添加一些集成测试时:

require 'spec_helper'

describe "Users" do
  describe "signup" do
    describe "failure" do
      it "should not make a new user" do
        lambda do
          visit signup_path
          fill_in "Name", with: ""
          fill_in "Full name", with: ""
          fill_in "Email", with: ""
          fill_in "Password", with: ""
          click_button
          response.should render_template("users/new")
          response.should have_selector("div#error_explanation")
        end.should_not change(User, :count)
      end
    end
  end
end

我有失败:

Failures:

  1) Users signup failure should not make a new user
     Failure/Error: visit signup_path
     AbstractController::ActionNotFound:
       The action 'new' could not be found for UsersController
     # ./spec/requests/users_spec.rb:8:in `block (5 levels) in <top (required)>'
     # ./spec/requests/users_spec.rb:7:in `block (4 levels) in <top (required)>'

  2) User Create a user test4
     Failure/Error: User.create!(@attr)
     ActiveRecord::RecordInvalid:
       Validation failed: Email has already been taken
     # ./spec/models/user_spec.rb:28:in `block (3 levels) in <top (required)>'

Finished in 0.77216 seconds
5 examples, 2 failures

第一次失败很明显(我的控制器是空的)但为什么第二次发生?另外,如果我进行了通过的集成测试,则模型测试也通过了。我使用 rails 3.1.0.rc5 和 rspec 2.6.4。即使当我评论 a.should_not be_valid 行时,它也可以工作。完全看不懂。

编辑: 我知道这是验证问题,但为什么 test4 在此示例中有效:

require 'spec_helper'

describe User do
  before(:each) do
    @attr = { name: "johnkowalski", fullname: "John Kowalski", 
      email: "kowalski@example.com", password: "foobar" }
  end

  describe "Create a user" do

    it "test1" do
      User.create!(@attr)
    end

    it "test2" do
      User.create!(@attr)
    end

    it "test3" do
      User.create!(@attr)
      @p = { name: "testowy", fullname: "John Kowalski", 
      email: "kowalski@example.com", password: "foobar" }
      a = User.new(@p)
      a.should_not be_valid
    end

    it "test4" do
      User.count.should == 0
    end
    it "test5" do
      User.create!(@attr)
    end
  end
end

用户.rb:

class User < ActiveRecord::Base
  has_secure_password

  email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :name, presence: true, length: { maximum: 20 },
            uniqueness: { case_sensitive: false }
  validates :fullname, presence: true, length: { maximum: 30 }
  validates :email, format: { with: email_regex },
            uniqueness: { case_sensitive: false }, length: { maximum: 30 }
  validates :password, length: { in: 5..25 }

end

我找到了这些事情发生的原因。所以当我只运行模型测试时,我在日志中有类似的东西:

 (0.0ms)  RELEASE SAVEPOINT active_record_1
   (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."name") = LOWER('testowy') LIMIT 1
   (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."email") = LOWER('kowalski@example.com') LIMIT 1
   (0.1ms)  SELECT COUNT(*) FROM "users" 
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."name") = LOWER('johnkowalski') LIMIT 1
   (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."email") = LOWER('kowalski@example.com') LIMIT 1
  SQL (0.3ms)  INSERT INTO "users" ("created_at", "email", "fullname", "name", "password_digest", "updated_at") VALUES (?, ?, ?, ?, ?, ?)  [["created_at", Thu, 28 Jul 2011 13:09:48 UTC +00:00], ["email", "kowalski@example.com"], ["fullname", "John Kowalski"], ["name", "johnkowalski"], ["password_digest", "$2a$10$e1.3fifGcs7PALH1o0GQJ.Ny/QxCS9fRxDJ6NemGkwfFJCpsD51vy"], ["updated_at", Thu, 28 Jul 2011 13:09:48 UTC +00:00]]
   (0.0ms)  RELEASE SAVEPOINT active_record_1

但是当我运行这些测试和集成测试时,我在日志中发现了这一点:

 (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."email") = LOWER('kowalski@example.com') LIMIT 1
   (0.1ms)  SELECT COUNT(*) FROM "users" 
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  SELECT 1 FROM "users" WHERE LOWER("users"."name") = LOWER('johnkowalski') LIMIT 1
  CACHE (0.0ms)  SELECT 1 FROM "users" WHERE LOWER("users"."email") = LOWER('kowalski@example.com') LIMIT 1
   (0.0ms)  ROLLBACK TO SAVEPOINT active_record_1

所以用户对象是从内存而不是从数据库中获取的。但默认情况下,缓存在测试环境中被禁用,我有 config.action_controller.perform_caching = false 在环境/test.rb

在这种情况下如何禁用缓存?

【问题讨论】:

  • 这真的很奇怪,你在模型中进行了哪些验证?
  • GAH,不要使用test1test2 作为你的测试名称! rSpec DSL 的全部意义在于你应该用类似于自然语言的方式来描述你的测试。而不是it "test1",您应该始终使用it "should be invalid" 或其他一些实际描述性名称。

标签: ruby-on-rails ruby-on-rails-3 rspec


【解决方案1】:

总是很难猜测你对 rspec 了解多少,所以也许这一切你都非常了解。

但是:您确定您的spec_helper.rb 中有以下行:

config.use_transactional_fixtures = true

这将确保在每次测试后发布所有创建的模型。请注意,before(:each) 中的所有内容都发生在事务中(并且被回滚),而 before(:all) 中的内容不会(并且需要在 after(all) 中进行清理。

因此,如果您使用事务性固定装置,User.count == 0 实际上是正常的,因为所有创建都会回滚。

此外,在同一级别上创建用户四次也没有用,因为结果会(通常是相同的)。

其次,由于您似乎正在测试您的验证,我建议您看一下 shoulda,它提供了不错的快捷方式。例如。像

it { should validate_uniqueness_of :email }

【讨论】:

  • 是的,我的 spec_helper.rb 中有这个。而且我知道 User.count == 0 应该是有效的。我不明白的是为什么只有 test5 失败?我知道没有必要对同一件事进行 3 次测试。这些只是用于理解 rspec 的这种奇怪行为的测试。
  • @chg:好的,你知道这些,因为这很难从你的问题或个人资料中推断出来。因此,集成规范以某种方式与模型测试的结果相混淆。奇怪的。为什么只有 test4 或 test5?如果这是原因,它应该在第一次尝试时失败。如果集成测试通过会发生什么?您是否并行运行测试?尝试找出最简单的失败案例。
  • 我也遇到了一些奇怪的问题,即在奇怪的时间释放保存点。所以我将创建一个夹具,但随后日志显示保存点在下一行发出请求之前立即释放...
  • 如果你在 MySQL 上,它不支持嵌套事务。这些测试运行后,您需要手动清理数据库。看到这个答案:stackoverflow.com/questions/13161394/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
相关资源
最近更新 更多