簡體   English   中英

我應該寫這些測試用例嗎?

[英]Should I write these Test Cases?

這是我要測試的模型的架構:

create_table "retreats", force: :cascade do |t|
  t.string   "title"
  t.string   "tagline"
  t.string   "type_of"
  t.datetime "created_at",                 null: false
  t.datetime "updated_at",                 null: false
  t.string   "description"
  t.string   "schedule"
  t.boolean  "available",   default: true
end

這是撤退模型:

class Retreat < ApplicationRecord
  TYPES_OF_RETREATS = ['individual', 'group']
  validates :title, presence: true
  validates :type_of, presence: true, inclusion: {in: TYPES_OF_RETREATS,
    message: "%{value} is not a valid type."}

  has_many :testimonials, dependent: :destroy
  has_many :images, dependent: :destroy
  has_and_belongs_to_many :dates, class_name: "RetreatDate", foreign_key: 
   'retreat_id', association_foreign_key: 'retreat_date_id'
end

這些是我編寫的測試用例:

  test "retreat should not save without a title" do
    retreat = retreats(:no_title)
    assert_not retreat.save, "Saved a retreat without a title"
  end

  test "retreat should not save without a type" do
    retreat = retreats(:no_type)
    assert_not retreat.save, "Saved a retreat without a type"
  end

  test "retreat can have a tagline, description, schedule and available" do
    retreat = retreats(:all_attributes)
    assert retreat.save, "Retreat failed to save"
  end

  test "retreat type should be from the provided list" do
    retreat = retreats(:invalid_type)
    assert_not retreat.save, "Some other retreat got saved. It shouldn't 
     have gotten saved."
  end

  test "retreat can have many testimonials" do
    retreat = retreats(:one)
    retreat.testimonials << Testimonial.new(statement: 'this is my 
      testimonial', participant_name: 'abc')
    assert retreat.save, "Retreat did not save with the testimonials."
  end

  test "retreat can have many dates" do
    retreat = retreats(:one)
    retreat.dates.create({date: '02-08-2012'})
    retreat.dates.create({date: '02-08-2013'})
    assert retreat.save, "Retreat with multiple dates is not saving"
    assert_equal(2, retreat.dates.length, "Retreat isn't saving multiple 
       dates.")
  end

我正在尋找有關應為哪種測試用例編寫建議的建議。 我覺得我的一些測試用例是不必要的。 像測試用例一樣進行驗證很有意義,但是測試是否可以添加多個推薦書使我感到不舒服。

我可以這樣重寫前兩個測試用例:

test "retreat title and type_of must not be empty" do
  retreat = Retreat.new
  assert retreat.invalid?
  assert retreat.errors[:title].any?, "Title must exist"
  assert retreat.errors[:type_of].any?, "Type must exist"
end

編寫單元測試的最佳實踐是什么? 我該如何編寫更好的單元測試?

謝謝 :)

http://www.betterspecs.org/幫助我從測試入手。

我會說堅持測試您的業務規則。 因此,不要僅僅測試保存或關系,因為這些工作或關系是Rails框架的一部分。 但是,請執行以下測試規則:“可以有兩個日期”,“我希望能夠同時創建撤退和推薦”

我認為您需要在“外部”和“內部”之間建立更清晰的邊界。 Rails本身(或實際的ActiveRecord)在這里沒有幫助。 它污染了您的對象,並帶有很多職責,這些對象尚不清楚它們的所屬位置:ActiveRecord不是測試的最佳接口。

我遵循單元測試的規則:

僅測試自己的(公共)接口及其對直接協作者的影響。

編寫單元測試的通常做法是僅對被測對象(內部)進行測試,而不再對所有對象進行測試 被測對象(單元)與之合作的任何東西都是外部的:他們有自己獨立的單元測試。

這導致大量的嘲笑和存根。 一個典型的非AR示例是:

class BikeShed
  attr_accessor :color, :colorizer
  def initialize(color, colorizer = ColorFactory)
    @color = color
  end

  def discuss
    @color = ColorFactory.random
  end
end

測試看起來像:

class BikeShedTest < TestCase
  describe "#discuss" do
    it "changes color to a random color from ColorFactory" do
      subject.color_factory = stub("DefaultColor")
      subject.color_factory = color_factory
      color_factory.expects(:random).returns(color)

      subject.discuss

      assert_equal color, subject.color
    end
  end

  private

  def subject
    @subject ||= BikeShed.new
  end

  def color
    @color ||= stub("Color")
  end

  def color_factory
    @color_factory ||= stub("ColorFactory")
  end
end

我使用依賴注入來傳遞其所有協作者,並且僅測試主題是否以適當的方式與該關聯進行交互。 而已。 曾經

我之所以使用BikeShed ,是因為這是一個爭議很大的話題。 如果沒有適當的集成測試,那么這種測試方式是不好的,它可能導致您僅測試已正確設置存根的狀態。 這也可能導致相當快的“測試實施”。 但是,我真的很喜歡這種風格,因為它迫使您保持松散的耦合,並使API和職責保持小巧,專注和整潔。 諸如ActiveRecord中斷的內容。

ActiveRecord污染具有大量職責的模型。 驗證,存儲,回調,編組,映射到視圖文件,has-many等,作用域,緩存等。

因此,對於wrt ActiveRecord(和大多數Rails對象),我遵循:

Rails在超類中提供的一切都是協作者

我認為ActiveRecord::Base好像是一些外部API。 就像上面示例中的ColorFactory一樣。 盡管從技術上講這並不是真的正確:它也是我的API的一部分。 考慮一下:如果您繼承了Stripe::Payment ,例如在MonthlyPayment ,您將不會測試Stripe是否正確地從CC中收取資金,甚至連Strip都不會在其服務器上創建正確的付款。 那么為什么這與您的數據庫不同? ActiveRecord只是通往數據庫的門戶,就像Stripe::Payment一樣。

因此,在測試ActiveRecord時,我會考慮ActiveRecord提供的任何內容,作為外部API,我會對其進行模擬:

class ApplicationRecord < ActiveRecord::Base; end
class Retreat < ApplicationRecord
  validates :title, presence: true
  scope :nsfw -> { where("title LIKE '%nsfw%'") }
end

測試可能看起來像

class RetreatTest < TestCase
  describe ".nsfw" do
    it "selects only records whose title includes nsfw" do
      ActiveRecord::Base.expects(:where).with("title LIKE '%nsfw%'")
      subject.nsfw
    end
  end

  describe "#title" do
    it "is validated to be present" do
      subject.title = nil
      subject.validate
      assert_includes subject.errors["title"], "can't be blank"
    end
  end

  private

  def subject
    @subject ||= Retreat.new
  end
end

我們在這里看到三件重要的事情:

  1. 測試范圍僅是一項確定我們是否使用正確的消息和參數調用外部 ActiveRecord API的測試。 我們可以放心地假設ActiveRecord具有適當的測試,可以斷言當我們正確調用ActiveRecord時,它將從某些存儲中返回正確的屬性。 那不是我們的責任。 (但是集成測試應該斷言用戶的最終結果是經過適當過濾的視圖等)。
  2. validate這樣的測試只是測試我們是否正確配置了模型; 不幸的是,確定此配置的API太糟糕了,因此我們進行了一次驗證,以確認它對我們的主題設置了某些錯誤。
  3. 唯一性驗證比較困難,我們需要將ActiveRecord.any?存根ActiveRecord.any? 返回一個true,然后期待一個驗證.error出現。 例如。 但是我們絕不應該將記錄寫入數據庫,然后使用該設置來確定對象上的驗證錯誤:這很脆弱,我們正在測試許多完全不相關的東西。 例如,它存儲正確(AR的責任,不是我們的模型)或AR使用正確的where確定唯一性(AR / ORM的責任,不是我們的模型)。

請注意,這有點像“測試實現,但實際上不是這樣:我們正在測試是否以某種方式調用了外部API。這就是IMO單元測試的(也是唯一的)任務。集成測試可以在那里斷言所有這些“某些方式”都會導致正確的行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM