2011-09-24 27 views
66

Tôi đã bắt đầu hành trình với TDD trong Rails và đã gặp phải một vấn đề nhỏ liên quan đến các kiểm tra xác thực mô hình mà dường như tôi không tìm được giải pháp. Hãy nói rằng tôi có một mô hình dùng,Rails 3.1, RSpec: xác nhận mẫu thử nghiệm

class User < ActiveRecord::Base 
    validates :username, :presence => true 
end 

và một thử nghiệm đơn giản

it "should require a username" do 
    User.new(:username => "").should_not be_valid 
end 

này kiểm tra một cách chính xác xác nhận sự hiện diện, nhưng những gì nếu tôi muốn cụ thể hơn? Ví dụ: thử nghiệm full_messages về đối tượng lỗi ..

it "should require a username" do 
    user = User.create(:username => "") 
    user.errors[:username].should ~= /can't be blank/ 
end 

Mối quan tâm của tôi về lần thử đầu tiên (sử dụng should_not be_valid) là RSpec sẽ không tạo ra thông báo lỗi mô tả. Nó chỉ đơn giản nói "dự kiến ​​hợp lệ? Để trả về false, đã thành sự thật." Tuy nhiên, ví dụ thử nghiệm thứ hai có một nhược điểm nhỏ: nó sử dụng phương thức create thay vì phương thức mới để nhận được đối tượng lỗi.

Tôi muốn thử nghiệm của mình cụ thể hơn về những gì họ đang thử nghiệm, nhưng đồng thời không phải chạm vào cơ sở dữ liệu.

Bất kỳ ai cũng có bất kỳ đầu vào nào?

Trả lời

91

Trước tiên, tôi muốn nói rằng bạn có một cái tên độc ác.

Thứ hai, CONGRATULATIONS về bạn nỗ lực vào TDD với ROR Tôi hứa khi bạn bắt đầu, bạn sẽ không nhìn lại.

Các giải pháp nhanh chóng và dơ bẩn đơn giản nhất sẽ được để tạo ra một mô hình hợp lệ mới trước mỗi bài kiểm tra của bạn như thế này:

before(:each) do 
    @user = User.new 
    @user.username = "a valid username" 
end 

NHƯNG những gì tôi đề nghị là bạn thiết lập các nhà máy cho tất cả các mô hình của bạn sẽ tạo ra một mô hình hợp lệ cho bạn tự động và sau đó bạn có thể lộn xộn với các thuộc tính riêng lẻ và xem liệu xác thực của bạn. Tôi thích sử dụng FactoryGirl cho việc này:

Về cơ bản một khi bạn có được thiết lập thử nghiệm của bạn sẽ giống như thế này:

it "should have valid factory" do 
    FactoryGirl.build(:user).should be_valid 
end 

it "should require a username" do 
    FactoryGirl.build(:user, :username => "").should_not be_valid 
end 

Oh ya và đây là a good railscast giải thích tất cả tốt hơn so với tôi:

chúc may mắn :)


CẬP NHẬT: Tính đến version 3.0 cú pháp cho nhà máy cô gái có đã thay đổi. Tôi đã sửa đổi mã mẫu của mình để phản ánh điều này.

+2

Cảm ơn rất nhiều Matthew. Có cách nào để tiến gần hơn đến lỗi mà tôi đang thử nghiệm không? X.should_not be_valid có vẻ rất chung chung với tôi, và ai biết được liệu có cái gì khác xuống đường sẽ làm cho bản ghi không hợp lệ. Thử nghiệm này sau đó sẽ thất bại ở vị trí sai. Nhân tiện, tôi nghĩ tôi đã đánh dấu câu trả lời của bạn là được chấp nhận. Phải không? – Feech

+7

Phải, vì vậy đây là lý do tại sao tôi tranh luận cho các nhà máy. Bạn viết mã để tạo một người dùng hợp lệ một lần ở một nơi và sau đó bạn viết một bài kiểm tra để đảm bảo nó hợp lệ trước tất cả các bài kiểm tra cá nhân để đảm bảo bạn có thể vô hiệu hóa nó. Bằng cách đó, nếu vì một lý do nào đó bạn thay đổi mô hình của mình để nhà máy sản xuất dài hơn một người dùng hợp lệ, 'Factory.build (: user) .nould be_valid' sẽ thất bại và bạn sẽ biết bạn phải cập nhật nhà máy của bạn ... ? (và có bạn chấp nhận câu trả lời của tôi) – Matthew

+0

Giải thích hoàn hảo. Cảm ơn một lần nữa. – Feech

41

Cách dễ dàng hơn để kiểm tra tính hợp lệ của mô hình (và nhiều bản ghi hoạt động) là sử dụng đá quý như shoulda hoặc remarkable.

Họ sẽ cho phép để kiểm tra như sau:

describe User 

    it { should validate_presence_of :name } 

end 
+1

Điều này là tốt để kiểm tra rằng bạn có các hiệp hội trong các mô hình, nhưng lưu ý rằng nó sẽ không thực sự cố gắng để tạo ra một người dùng mà không có tên và kiểm tra tính hợp lệ của nó – brafales

+3

@ brafales không thực sự, afaik đó là chính xác những gì shoulda hiện: nó sẽ cố tạo đối tượng bằng tên trống và nó sẽ gây ra lỗi. – nathanvda

+2

Bạn nói đúng, có vẻ như tôi đã đọc mã sai https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb – brafales

0

tôi đã xử lý theo truyền thống kỹ thuật nội dung sai sót trong tính năng hoặc yêu cầu thông số kỹ thuật.Vì vậy, ví dụ, tôi có một spec tương tự mà tôi sẽ ngưng tụ dưới đây:

Feature Spec Ví dụ

before(:each) { visit_order_path } 

scenario 'with invalid (empty) description' , :js => :true do 

    add_empty_task         #this line is defined in my spec_helper 

    expect(page).to have_content("can't be blank") 

Vì vậy, sau đó, tôi phải thử nghiệm mô hình spec của tôi cho dù một cái gì đó có giá trị, nhưng sau đó tôi đặc tả tính năng kiểm tra đầu ra chính xác của thông báo lỗi. FYI, các thông số tính năng này yêu cầu Capybara có thể được tìm thấy here.

15

Hãy thử điều này:

it "should require a username" do 
    user = User.create(:username => "") 
    user.valid? 
    user.errors.should have_key(:username) 
end 
+0

Đây là yêu thích của tôi, rất chắc chắn, kiểm tra khóa và không phải là thông báo, chi tiết là – ecoologic

+3

bạn chỉ có thể sử dụng user = User.new (: username => "") để tránh nhấn db –

+0

@TaufiqMuhammadi 'new' sẽ không đạt xác thực cấp db, ví dụ một ràng buộc chỉ số duy nhất. – mnort9

2

trong phiên bản mới rspec, bạn nên sử dụng mong đợi thay vì nên, nếu không bạn sẽ nhận được cảnh báo:

it "should have valid factory" do 
    expect(FactoryGirl.build(:user)).to be_valid 
end 

it "should require a username" do 
    expect(FactoryGirl.build(:user, :username => "")).not_to be_valid 
end 
+0

Bạn cũng nên sử dụng các động từ hiện tại thay vì trong các tên ví dụ. Ở trên có thể được viết lại là '" có một nhà máy hợp lệ "' và '" yêu cầu tên người dùng "'. – BrunoFacca

0

Giống như @nathanvda nói, tôi sẽ tận dụng lợi thế của Viên đá quý Shoulda Matchers của Thoughtbot. Với sự rung lắc đó, bạn có thể viết bài kiểm tra của mình theo cách sau đây để kiểm tra sự hiện diện, cũng như bất kỳ thông báo lỗi tùy chỉnh nào.

RSpec.describe User do 

    describe 'User validations' do 
    let(:message) { "I pitty da foo who dont enter a name" } 

    it 'validates presence and message' do 
    is_expected.to validate_presence_of(:name). 
     with_message message 
    end 

    # shorthand syntax: 
    it { is_expected.to validate_presence_of(:name).with_message message } 
    end 

end 
Các vấn đề liên quan