【问题标题】:What black magic is happening in my RSpec email uniqueness test?我的 RSpec 电子邮件唯一性测试中发生了什么黑魔法?
【发布时间】:2013-02-17 10:01:27
【问题描述】:

我关注The Ruby on Rails Tutorial Book by Michael Hartl,对其进行了修改,添加了用于用户身份验证的设计,但遇到了电子邮件唯一性测试的问题。

# spec/models/user_spec.rb

require 'spec_helper'

describe User do
  before do
    @user = User.new(username: 'ExampleUser',
                     email:    'user@example.com',
                     password: 'passworD123')
    @user.save
  end

  subject { @user }

  it { should respond_to(:email) }
  it { should respond_to(:name) }
  it { should respond_to(:username) }
  it { should respond_to(:password) }

  it { should be_valid }

  describe 'username is already taken' do
    before do
      user_with_same_username = @user.dup
      user_with_same_username.username = @user.username.upcase
      user_with_same_username.email = 'a@b.c'
      user_with_same_username.save
    end

    it { should_not be_valid }
  end

  describe 'email address is already taken' do
    before do
      user_with_same_email = @user.dup
      user_with_same_email.username = 'differentUsername'
      user_with_same_email.email = @user.email.upcase
      user_with_same_email.save
    end

    it { should_not be_valid }
  end

  .
  .

失败:

  1) User email address is already taken
     Failure/Error: it { should_not be_valid }
       expected valid? to return false, got true
     # ./spec/models/user_spec.rb:104:in `block (3 levels) in <top (required)>'

电子邮件的唯一性已设置,但不需要,因为 Devise 已经这样做了。我将user_with_same_email.save 更改为user_with_same_email.save!,然后我收到电子邮件地址的验证错误,因为它已被占用:

1) User email address is already taken
   Failure/Error: user_with_same_email.save!
   ActiveRecord::RecordInvalid:
     Validation failed: Email has already been taken
   # ./spec/models/user_spec.rb:101:in `block (3 levels) in <top (required)>'

user_with_same_email.save 的返回值为 false,it { should_not be_valid } 会检查这种情况,但为什么测试仍然失败?

【问题讨论】:

    标签: ruby-on-rails ruby capybara unique rspec2


    【解决方案1】:

    关于您的实际问题,原因很简单:您没有在正确的 subject 上进行测试

    其他指南:

    • 如果您知道对象无效,请不要保存它,您只是在浪费时间。

    • 对于您的第一个规范也是如此,您真的需要一个持久对象吗?我猜不是。。

    • 最后但同样重要的是:考虑使用工厂,它是可重复使用的,可以让您进行更一致的测试。

    您的规格可能如下所示:

    require 'spec_helper'
    
    describe User do
      let(:user_attributes) { {
          username: 'ExampleUser',
          email:    'user@example.com',
          password: 'passworD123'
        }
      }
    
      subject(:user) { User.new(user_attributes) }
    
      it { should respond_to(:email) }
      it { should respond_to(:name) }
      it { should respond_to(:username) }
      it { should respond_to(:password) }
      it { should be_valid }
    
      context 'with existing user in db' do
        before(:each) { user.save }
    
        describe 'username is already taken' do
          subject(:user_with_same_username) { User.new(user_attributes.merge(email: 'another@email.com')) }
          it { should_not be_valid }
        end
    
        describe 'email address is already taken' do
           subject(:user_with_same_email) { User.new(user_attributes.merge(username: 'another name')) }
           it { should_not be_valid }
        end
      end
    end
    

    【讨论】:

    • 谢谢!这更有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多