新手问题 使用 RSpec 测试时遇到一个 “段错误(核心已转储)“问题,弄了很久搞不定,新手求助

匿名 · 2014年10月10日 · 最后由 hooozer 回复于 2014年10月12日 · 3708 次阅读

1:ubuntu 各文件已是最新。 2:搜了其他解决办法,清空 rvm(remove all),重新安装 ruby,建 gemset,然后 bundle update/install,还是不行。 3:bundle exec rspec spec/ -->出现一个红色 F 错误,后面 “段错误(核心已转储)“ 4:bundle exec rspec spec/requests/user_pages_spec.rb -->测试通过 5:bundle exec rspec spec/requests/authentication_pages_spec.rb,分别出现 Control frame information、C level backtrace information、Other runtime information、Process memory map 这几大块错误信息,总共 n 多行。 6:应用运行无错。

tiger@tigerPC:~/sample_app$ bundle exec rspec spec/
No DRb server is running. Running in local process instead ...
........[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
..............................................F段错误 (核心已转储)
tiger@tigerPC:~/sample_app$ bundle exec rspec spec/requests/user_pages_spec.rb
No DRb server is running. Running in local process instead ...
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
..................

Finished in 1.45 seconds
18 examples, 0 failures

Randomized with seed 43555

tiger@tigerPC:~/sample_app$ bundle exec rspec spec/requests/authentication_pages_spec.rb
No DRb server is running. Running in local process instead ...
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
........../home/tiger/.rvm/rubies/ruby-2.0.0-p576/lib/ruby/gems/2.0.0/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:179: [BUG] vm_call_cfunc - cfp consistency error
ruby 2.0.0p576 (2014-09-19 revision 47628) [x86_64-linux]

-- Control frame information ------------------

Gemfile 如下:

source 'https://rubygems.org'
ruby '2.0.0'
gem 'rails', '4.0.0'
gem 'bootstrap-sass', '2.3.2.0'

group :development, :test do
  gem 'sqlite3', '1.3.7'
  gem 'rspec-rails', '2.13.1'
  gem 'guard-rspec', '2.5.0'
  gem 'spork-rails', github: 'railstutorial/spork-rails'
  gem 'guard-spork', '1.5.0'
  gem 'childprocess', '0.5.3'
end

group :test do
  gem 'selenium-webdriver', '~>2.35.1'
  gem 'capybara', '2.1.0'
  gem 'factory_girl_rails', '4.2.1'
end

gem 'sass-rails', '4.0.3'

gem 'uglifier', '2.1.1'

gem 'coffee-rails', '4.0.0'

gem 'therubyracer', platforms: :ruby

gem 'jquery-rails', '2.2.1'

gem 'turbolinks', '1.1.1'

gem 'jbuilder', '1.0.2'

group :doc do

  gem 'sdoc', '0.3.20', require: false
end

gem 'bcrypt-ruby', '3.0.1'

authentication_pages_spec.rb 如下:

require 'spec_helper'

describe "AuthenticationPages" do
  subject { page }

  describe "signin page" do
    before { visit signin_path }
    it { should have_content('Sign in') }
    it { should have_title('Sign in') }
  end

  describe "signin" do
    before { visit signin_path }

    describe "invalid" do
      before { click_button "Sign in" }

      it { should have_title("Sign in") }
      it { should have_selector("div.alert.alert-error"), text: "invalid" }

      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_selector('div.alert.alert-error') }
      end
    end

    describe "valid" do
      let(:user) { FactoryGirl.create(:user) }
      before do
        fill_in "Email", with: user.email.upcase
        fill_in "Password", with: user.password
        click_button "Sign in"
      end

      it { should have_title(user.name) }
      it { should have_link('Profile', href: user_path(user)) }
      it { should have_link('Sign out'), href: signout_path }
      it { should_not have_link('Sign in'), href: signin_path }

      describe "after signouting" do

        before { click_link 'Sign out' }
        it { should have_link('Sign in') }

      end

    end

  end

  describe "with valid information" do
    let(:user) { FactoryGirl.create(:user) }
    before { sign_in user }

    it { should have_link("Profile", href: user_path(user)) }
    it { should have_link("Settings", href: edit_user_path(user)) }
    it { should have_link("Sign out", href: signout_path) }
    it { should have_title(user.name) }

    it { should_not have_link("Sign in", href: signin_path) }
  end

  describe "访问权限控制" do
    describe "对于未登录的用户" do
      let(:user) { FactoryGirl.create(:user) }

      describe "试图访问编辑页面时" do
        before do
          visit edit_user_path(user)
          fill_in "Email", with: user.email
          fill_in "Password", with: user.password
          click_button "Sign in"
        end

        describe "在登录后" do
          it "应该转向之前用户想访问的页面" do
            expect(page).to have_title("Edit user")
          end
        end
      end

      describe "在users控制器" do
        describe "访问编辑页面" do
          before { visit edit_user_path(user) }

          it { should have_title("Sign in") }
        end

        describe "点击更新按钮" do
          before { patch user_path(user) }
          it "应该跳到登录界面" do
            expect(response).to redirect_to(signin_path)
          end
        end

      end
    end

    describe "试图更改其他用户的资料" do
      let(:user) { FactoryGirl.create(user) }
      let(:wrong_user) {FactoryGirl.create(:user, email: "wrong_user@qq.com")}
      before { sign_in user, no_capybara: true }

      describe "访问users#edit page" do
        before { visit edit_user_path(wrong_user) }
        it { should_not have_title(full_title("Edit user")) }
      end

      describe "提交一个patch请求给users#update" do
        before { patch user_path(wrong_user) }
        specify { expect(response).to redirect_to(root_path) }
      end
    end

  end
end

问题是在 No DRb server is running. Running in local process instead ... 上, 股沟之

匿名 #2 · 2014年10月10日

#1 楼 @dddd1919 谢谢,不是这个的问题,这个 drb server 是一个加速测试的工具,以前没用也没关系。。

匿名 #3 · 2014年10月11日

自己解决了。。 一个方法的参数少了个 : ,应该是:user

describe "试图更改其他用户的资料" do
      let(:user) { FactoryGirl.create(user) }

又费了好几个小时,,虽是小错误但收获颇多,,深感调 bug 的不容易。。也感慨自己粗心大意

rspec 报这个错一般是因为使用了为赋值的变量名。

避免方法是经常运行,缩小查错的范围。

#3 楼 @hooozer #4 楼 @birdfrank Rspec 类似的问题太不合理, 怎么着也不能导致 Ruby 解释器出现问题呢.

匿名 #6 · 2014年10月11日

#4 楼 @birdfrank 是的,谢谢经验分享。我后面也是这样找到的

匿名 #7 · 2014年10月11日

三楼我贴出的是出错的代码块,正确的如下:

describe "试图更改其他用户的资料" do
      let(:user) { FactoryGirl.create(:user) }
匿名 #8 · 2014年10月11日

#4 楼 @birdfrank 不过我刚才又复现了这个错误,有新的发现,如果把错误代码块的 (create 后面的) 参数换成如下:

describe "试图更改其他用户的资料" do
      let(:user) { FactoryGirl.create(m) }

这时,ruby 解释器层不会崩溃,终端里是 Rspec 正常的报错行为:

Failure/Error: let(:user) { FactoryGirl.create(m) }
     NameError:
       undefined local variable or method `m' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_4::Nested_2::Nested_1:0x00000005253320>

这说明之前如下代码中的 user 是已被赋值的

let(:user) { FactoryGirl.create(user) }

然后我的 spec 目录下的 factories.rb 内容如下:

FactoryGirl.define do
  factory :user do
    sequence(:name) { |n| "Person #{n}" }
    sequence(:email) { |n| "Person_#{n}@gmail.com" }
    password "foobar"
    password_confirmation "foobar"
  end
end

从上面可以看出,FactoryGirl.create 这个方法是需要一个 Symbol 的,所以我觉得: 是不是 FactoryGirl 这个 gem 这里的代码不够健壮,没有进行必要的类型检查,不关 Rspec 的事呢? #5 楼 @lyfi2003

@hooozer 你最后贴的问题不关 symbol 的事, m 是什么内容连 Ruby 都不明白, 还到不了 FactoryGirl。

主贴里面最明显的问题就是let在这里必须换成let!。 这个必须改。 在 Capybara 请求之前数据必须实际存在于数据库里。

其次你的创建正常用户部分的代码重复,可以提到最高阶的 before block 然后把其余的删掉。 这个可选。

@hooozer 从最根本的原因来说,段错误一般是由于某个程序访问了不属于自己的内存块引起的。如果是 C 一类需要自己管理内存的语言,那可能是使用了已释放的内存,或者指针出错。

到 ruby 语言,我猜测应该是程序写错(比如少了一个冒号,使 symbol 变成了变量),从而引起内存访问错误。但是 ruby 解释器应该处理这种错误,抛出诸如 “undefined local variable or method” 一类的错误,而不应该产生段错误。我 猜测 是不是由 spring 引起的呢?

我比较确定的一点是,每次 RSpec 报段错误的时候,最后查下来都是把变量名或属性名打错了。但不是每次把变量名或属性名打错都会发生段错误。这是一个观察到的现象。产生这个现象的原因有待进一步研究。

匿名 #11 · 2014年10月12日

#9 楼 @billy 8 楼贴的我刚才发现有处输入错误,已改,第一,二段代码里应该都是FactoryGirl.create(m)不好意思。谢指点 :),关于代码冗余,现在我还在看 RoR tutorial,后面应该会重构的。

@hooozer 重点不是亢余。 是let要改成let!let是懒惰的,不呼叫不工作, let!会在定义时工作。 这个情景必须先有数据在数据库里面, 访问才能看得到东西。

匿名 #13 · 2014年10月12日

#12 楼 @billy 我还是新手,教程上还有好多东西不理解,包括 Rspec。教程上用的是let,而且现在我测试各个测试文件都没问题了。我的真正的错误在 3 楼 已解决。

匿名 #14 · 2014年10月12日

#12 楼 @billy 不过现在换成let!,也不报错,没问题。

匿名 #15 · 2014年10月12日

#12 楼 @billy 还有 7 楼。嘿嘿

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册