测试的哲学
- 测试应该是可靠的
- 测试应该容易书写
- 测试应该容易理解
一些妥协
- 速度不是测试中关注的重点
- 过于DRY的代码不是测试中关注的重点 参考原文
Model的Specs
- 为当前的Model创建一个spec
- 可以使用factories来简化测试数据的维护和创建
- 为Model的validation,class,以及instance method写能够通过的测试用例
get started
A model spec should include tests for the following
factory默认生成的对象必须合法
describe Contact
it "has a valid factory"
it "is invalid without a firstname"
it "is invalid without a lastname"
it "returns a contact's full name as a string"
- 每一个测试用例只测试一件事情
- 每一个测试用例都必须明确
- 每一个用例的描述都以动词开头而不是should
####可以使用Factorygirl创建数据,然后使用Faker
gem 可以用来创建随即的数据
require 'faker'
FactoryGirl.define do
factory :contact do |f|
f.firstname { Faker::Name.first_name }
f.lastname { Faker::Name.last_name }
end
end
不能通过validation的数据,应该是不合法的
可以使用Factory.build()
实例化一个新的model,但是并不保存它
# spec/models/phone_spec.rb
it "does not allow duplicate phone numbers per contact" do
contact = Factory(:contact)
Factory(:phone, contact: contact, phone_type: "home", number: "785-555-1234")
Factory.build(:phone, contact: contact, phone_type: "mobile", number: "785-555-1234").should_not be_valid
end
Validation的部分
# app/models/phone.rb
validates :phone, uniqueness: { scope: :contact_id }
测试validation的时候要记住,不光是测试所有数据都合法的happy path,同样还需要测试错误的条件。
类和成员方法要能够按预期运行
def name
[firstname, lastname].join " "
end
为这个特性编写测试用例
it "returns a contact's full name as a string" do
contact = Factory(:contact, firstname: "John", lastname: "Doe")
contact.name.should == "John Doe"
end
测试类方法
特册应该返回name以给定字母开头的contact的list
# app/models/contact.rb
def self.by_letter(letter)
where("lastname LIKE ?", "#{letter}%").order(:lastname)
end
然后测试它
# spec/models/contact_spec.rb
require 'spec_helper'
describe Contact do
# validation examples ...
it "returns a sorted array of results that match" do
smith = Factory(:contact, lastname: "Smith")
jones = Factory(:contact, lastname: "Jones")
johnson = Factory(:contact, lastname: "Johnson")
Contact.by_letter("J").should == [johnson, jones]
end
end
参考资料: How I learned to test my Rails applications, Part 3: Model specs