Chris Zetter是FutureLearn產品組的一名開發者,他為我們講述了自己的小組為了使
功能測試兼具可維護性與可讀性,在把Cucumber替換為RSpec之后是如何來編寫測試的。
測試是建立與維護一個大型平臺不可或缺的一部分。每當我們為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' |
我們樂于使用Cucumber因為它可以使根據用戶故事編寫測試變得簡單易行,而且寫完的測試通俗易懂。然而使用Cucumber也有些許不足之處。首先,我們已經在項目里使用了RSpec,再引入Cucumber意味著又要多維護一個測試框架;其次,由于兩者的DSLs和測試運行器不同,在他們之間進行腦筋切換又會帶來額外開銷;最后,我們特別不喜歡Cucumber所使用的正則表達式,因為同
Ruby的標準方法調用相比,它們使測試變得更加晦澀難懂。
編寫更好的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 end |
它們總是趨于變得很長,使得難以辨明其究竟在測試些什么。而且難以區分諸如Arrange, Act, Assert(在Cucumber里又被稱為’Given’、’When’和’Then’)這些部分。我們試過在代碼中這些步驟里添加注釋,但它們就和通常那些程序代碼里的注釋一樣不盡如人意:一段時間之后這些注釋就變得與實際代碼不同步了。
一般來說,如果是在程序里別的地方寫出這么長的方法,我們就會有所警覺,并且通常會采用提取方法的辦法進行重構。何不也這么做呢?讓我們依據Cucumber步驟的風格,把這些代碼也提取成一個個方法吧。
feature 'Enrolment' do scenario 'Enrolling in a course' do 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 end def given_there_is_a_course @course = FactoryGirl.create(:course) end def and_i_am_logged_in_as_a_learner @learner = FactoryGirl.create(:learner) login_as @learner end def when_i_enrol_on_a_course visit course_path(@course) find('.join').click expect(page).to have_content('Thanks for joining!') end def then_the_course_should_appear_in_my_courses visit '/' expect(page).to have_main_header('My Courses') expect(page).to have_content(@course.full_title) end end |
我們有何發現
我們移除了全部的Cucumber功能測試,并把它們中大部分用新式的RSpec features加以重寫。這樣一來即可保證擁有Cucumber所提供的優秀的可讀性,又使得測試變得更加便于編寫和維護。
我們做了一個慎重的決定,不把各個features文件里提取的方法進行復用,因為擔心這么做會使得測試難于理解。我們發現在編寫一個feature下的多條scenario時,會不自覺的就想要進行代碼復用。