12/08/2018, 14:23

Kinh nghiệm sử dụng Rspec

Xin chào mọi người, hôm nay mình xin viết một số kinh nghiệm của mình khi sử dụng Rspec. Thứ nhất, khi test nhiều trường hợp với 1 đối tượng giống nhau thì nên sử dụng subject {} ví dụ: BAD it { expect(assigns('message')).to match /it was born in Belville/ } GOOD subject { ...

Xin chào mọi người, hôm nay mình xin viết một số kinh nghiệm của mình khi sử dụng Rspec.

Thứ nhất, khi test nhiều trường hợp với 1 đối tượng giống nhau thì nên sử dụng subject {}

ví dụ:

BAD

it { expect(assigns('message')).to match /it was born in Belville/ }

GOOD

subject { assigns('message') }
it { is_expected.to match /it was born in Billville/ }

Rspec cũng có khả năng định nghĩa 1 object

subject(:hero) { Hero.first }
it "carries a sword" do
  expect(hero.equipment).to include "sword"
end

Khi bạn phải định nghĩa object để sử dụng trong các test của mình, thay vì sử dụng các khối before thì bạn nên sử dụng let hay let!, đây là cách để bạn sử dụng các object mình 1 cách lazy load. Nghĩa là sẽ chỉ được định nghĩa khi chúng được gọi tới lần đầu tiên và sẽ được cached lại để sử dụng tiếp cho đến khi test chạy xong.

BAD

describe '#type_id' do
  before { @resource = FactoryGirl.create :device }
  before { @type     = Type.find @resource.type_id }

  it 'sets the type_id field' do
    expect(@resource.type_id).to equal(@type.id)
  end
end

GOOD

describe '#type_id' do
  let(:resource) { FactoryGirl.create :device }
  let(:type)     { Type.find resource.type_id }

  it 'sets the type_id field' do
    expect(resource.type_id).to equal(type.id)
  end
end

Hay sử dụng let để khởi tạo các object và chỉ sử dụng khi cần nhé

GOOD

context 'when updates a not existing property value' do
  let(:properties) { { id: Settings.resource_id, value: 'on'} }

  def update
    resource.properties = properties
  end

  it 'raises a not found error' do
    expect { update }.to raise_error Mongoid::Errors::DocumentNotFound
  end
end

Chủ đề này đã được đề cập đến khá nhiều rồi nhưng mình vẫn muốn nhắc lại vì vẫn thấy mọi ngươi sử dụng fixture hay thậm chí còn tạo object trong spec như thế này:

before {@user = User.new}

BAD

user = User.create(
  name: 'Genoveffa',
  surname: 'Piccolina',
  city: 'Billyville',
  birth: '17 Agoust 1982',
  active: true
)

GOOD

user = FactoryGirl.create :user

Cách này rất tiện lợi, giúp cho code spec của bạn gọn hơn và bạn cũng dễ dàng tạo ra các object phục vụ việc test. Mà không phải nghĩ nhiều đến chuyện attribute này mình nên đặt là gì, vì bạn sẽ định nghĩa trước ở trong các file ở /spec/factories.

should là cú pháp cũ và bây giờ không còn được sử dụng rộng rãi nữa, tuy nhiên khi các bạn tim kiếm về rspec thì vẫn còn gặp khá nhiều example hay tuts viết theo cú pháp này. Các bạn nên sử dụng cú pháp mới là expect. Để ngăn việc should vẫn hợp lệ khi chạy test bạn có thể dùng các gem như should_not hay the should_clean gem

BAD

it 'should not change timings' do
  consumption.occur_at.should == valid.occur_at
end

GOOD

it 'does not change timings' do
  expect(consumption.occur_at).to equal(valid.occur_at)
end

Ngoài ra, mình thấy nhiều bạn sử dụng context và describe khá loạn và lúng túng khi dùng 2 từ khá này trong rspec. Theo mình thì dù là context hay describe thì cũng chỉ là để gom những test chung lại. Tuy nhiên, theo mình hiểu thì describe là để gói vấn đề, ví dụ:

describe "#validation"
    ...
end

là để gói các test về validation, và context sẽ gói ở phạm vi nhỏ hơn và nên ở bên trong describe. Ví dụ:

describe "#validation"
    context "when password is nil" do
        it {is_expected.not_to be_valid}
    end
end

Với những điều mình chia sẻ ở trên, mong là có thể giúp cho những bạn mới tìm hiểu về Rspec có thể viết spec tốt hơn. Cám ơn các bạn đã đọc bài của mình.

0