2

序言軌,SRP,和單元測試

這是我第一次嘗試建立與心中SRP一個應用程序,真的試圖用測試來驅動代碼的網站,而不是開始我數據架構(ActiveRecord),然後構建適合的應用程序。

但我遇到了問題。我已經訂閱並觀看了很多銷燬所有軟件的屏幕錄像,理論上我喜歡他所講的內容,但我在實踐中遇到了麻煩。手頭

問題,我知道我的應用程序的主要功能將搜索基於位置配置文件。所以我爲此寫了一個簡單的Cucumber功能(故意暫時放棄路由/控制器/等等,以簡化手頭的任務)。

search.feature:

Feature: Search for profiles 

    Scenario: By zipcode 
    When I search for 90210 
    Then I will see profiles near 90210 

search_steps.rb:

When /^I search for 90210$/ do 
    @profiles = ProfileSearch.new.near_location(90210).all 
end 

Then /^I will see profiles near 90210$/ do 
    pending # express the regexp above with the code you wish you had 
end 

沒有問題,現在到規格:

profile_search_spec.rb:

require_relative '../../app/services/profile_search' 

describe ProfileSearch do 
    it "finds nearby profiles" 
    it "does not find far away profiles" 
end 

profile_search .rb:

class ProfileSearch 
end 

我已經使用了一個ProfileSearch類的原因有幾個。

  1. 在ActiveRecord(單一職責原則)之外儘可能多地移動業務邏輯似乎是正確的做法。
  2. PORO使得測試更快(無需加載Rails)。
  3. 我打算在不久的將來使用ElasticSearch或Solr,並希望界面保持不變。

我不確定接下來要做什麼。 ProfileSearch顯然取決於Profile模型,我很確定這將是ActiveRecord。

所以問題是我開始specing和建設Profile,並開始在我的測試中加載Rails?這似乎是最簡單的選擇,但有關它似乎是錯誤的。我覺得我會設計和構建我的應用尚未特別要求的行爲。我不得不考慮領域,關係和存儲等等,所有這些我的應用程序目前都不應該關心。

或者我應該在我的ProfileSearch規範中使用存根/嘲all對Profile的所有調用,並確保調用正確的方法?這也看起來是錯誤的,因爲我不會真正測試行爲,而且即使預期會出現相同的行爲,切換到Solr或ElasticSearch時也必須重寫測試。

或者我應該真正創造建立他的維基的事情時,不使用ActiveRecord暫且但正確響應所有正確的方法爲Bob大叔表現出了工作檔案模式?這似乎是理論上可能是最好的方法,但知道我將在未來使用ActiveRecord,它似乎也是相當多餘的。

或者...他媽的它扔在ActiveRecord的模型中的方方面面:\

有這麼多的模式,原則和最佳實踐漂浮在我的頭上,我不知道跆拳道做。

你會怎麼做?

回答

1

首先,你需要選擇你的測試方法:

  • 黃瓜是專爲BDD(外而內)測試。黃瓜情景是爲了鍛鍊你的整個堆棧(網頁,控制器,模型,數據庫 - 無論你的堆棧),而不是作爲單元測試,你似乎做以上。所以,如果你寫的第一件事是黃瓜的情況下,你需要將所有層的調入是進行第一次場景通過。無論是使用Cucumber(我最喜歡的)還是RSpec功能規格,我都會這樣做。完成之後,您可以自由地重構以滿足您喜歡的任何設計標準,並且可以使用單元測試來測試詳細的需求。

  • 或者,你可以挑選堆棧中最棘手的部分,存在的單元測試,以及單元測試層和最終驗收測試,直到你有一個完整的應用程序。一方面,在投資簡單零件之前,證明您可以使棘手的零件工作,這可能是一個好主意。另一方面,我發現,當我想在組件接口沒有工作的驗收測試,我總是猜錯的話,所以我不做這種方式。

無論哪種方式,你的目標是ProfileSearch類返回Profile實例,但不承諾他們是ActiveRecord對象或其他任何持久性特異性。你如何處理在測試這些類取決於測試的類型:

  • 如果使用驗收規範(黃瓜或RSpec的功能規格),他們將不會使用存根,他們將利用一切真正的實現類,和他們會加載Rails,因爲這是他們的要點,這就是他們的設計。對不起,他們會很慢。除了需要指定重要場景之外,不要再編寫它們。

  • 在使用ProfileSearch類單元測試,您可以存根出去,速度返回波羅斯。 (如果您使用RSpec的護欄,require 'spec_helper'在這些規範不rails_helper避免加載Rails在自己運行它們。)

  • 做出的ProfileSearch本身通過單元測試,最簡單的方法可能是隻是讓Profile ActiveRecord模型,並有ProfileSearch使用Profile的ActiveRecord的功能和返回Profile真實情況。這些規格也需要require 'rails_helper'

+0

完全支持的第一個點。我們稱這些測試爲「[皮下測試]」(http://martinfowler.com/bliki/SubcutaneousTest)。HTML)「,並且通常從控制器開始,並通過堆棧完全集成到真正的數據庫(通常是嵌入式版本,因此它可以在內存中運行),就像Dave說的那樣,它可以很好地重構控制器的許多部分模型和持久性問題可以重構,而且測試不需要改變,當有IO抽象時,這些問題通常會被嘲笑,因爲它們並不重要,我在構建這些方法時採取了測試優先的方法。 – 2016-12-22 14:56:11