測試是建立與維護一個大型平台不可或缺的一部分。每當我們為futurelearn這個平台增添新功能時,我們都會編寫自動化的功能測試來記錄這些新功能是如何運作的,并確定他們不運轉時我們也能知曉。
令人愛恨交加的cucumber
cucumber是一款用來編寫功能測試的常用工具,每當我們開啟項目時它都是我們的不二選擇。它可以讓我們以使用者的視角編寫出高層級的行為驅動測試。
feature: enrolment
scenario: enrolling in a course
given there is a course
and i am logged in as a learner
when i enrol on a course
then the course should appear in 'my courses'
編寫更好的rspec features
那麼,我麼該如何在不失測試可讀性的前提下停用cucumber呢?
我們已經開始使用rspec features來替代cucumber,它們通常看起來會是這樣:
feature 'enrolment' do
scenario 'enrolling in a course' do
course = factorygirl.create(:course)
learner = factorygirl.create(:learner)
login_as learner
visit course_path(course)
find('.join').click
expect(page).to have_content('thanks for joining!')
visit '/'
expect(page).to have_main_header('my courses')
expect(page).to have_content(course.full_title)
end
它們總是趨于變得很長,使得難以辨明其究竟在測試些什麼。而且難以區分諸如arrange, act, assert(在cucumber裡又被稱為’given’、’when’和’then’)這些部分。我們試過在代碼中這些步驟裡添加注釋,但它們就和通常那些程式代碼裡的注釋一樣不盡如人意:一段時間之後這些注釋就變得與實際代碼不同步了。
一般來說,如果是在程式裡别的地方寫出這麼長的方法,我們就會有所警覺,并且通常會采用提取方法的辦法進行重構。何不也這麼做呢?讓我們依據cucumber步驟的風格,把這些代碼也提取成一個個方法吧。
given_there_is_a_course
and_i_am_logged_in_as_a_learner
when_i_enrol_on_a_course
then_the_course_should_appear_in_my_courses
def given_there_is_a_course
@course = factorygirl.create(:course)
def and_i_am_logged_in_as_a_learner
@learner = factorygirl.create(:learner)
login_as @learner
def when_i_enrol_on_a_course
visit course_path(@course)
def then_the_course_should_appear_in_my_courses
expect(page).to have_content(@course.full_title)
我們有何發現
我們移除了全部的cucumber功能測試,并把它們中大部分用新式的rspec features加以重寫。這樣一來即可保證擁有cucumber所提供的優秀的可讀性,又使得測試變得更加便于編寫和維護。
我們做了一個慎重的決定,不把各個features檔案裡提取的方法進行複用,因為擔心這麼做會使得測試難于了解。我們發現在編寫一個feature下的多條scenario時,會不自覺的就想要進行代碼複用。
最新内容請見作者的github頁:http://qaseven.github.io/