iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
自我挑戰組

追憶JS年華系列 第 27

Day-27 特集:測試驅動開發 TDD 

所謂測試驅動開發(Test-driven development, TDD),即「先寫測試再開發」,寫一段程式,以測試功能是否正常,確保程式依照預期行為運作。有關基本原理及JavaScript中的使用,詳參延伸閱讀(這裡)。本文另以Ruby語言展示之。

撰寫測試應吻合3A原則,即Arrange(安排好)、Act(踢他兩下)、Assertion(斷言/條件)。

JavaScript的測試實例

const moreThanChars = (chars, n) => /.{8,}/.test(chars)

test("應該要超過 8 個字 part 1", () => {
  let result = moreThanChars("abc", 8)
  expect(result).toBe(false)
})

test("應該要超過 8 個字 part 2", () => {
  let result = moreThanChars("abc283209138021832", 8)
  expect(result).toBe(true)
})

function test(title, callback) {
  try {
    callback() //萬一上面的callback壞了
    console.log(`✓ ${title}`);  //沒壞印這個
  } 
  catch(err) {
    console.error(`✗ ${title}`)  //壞了印這個
    console.error(err)  //印出來
  }
}

function expect(result) {
  return {
    toBe: (expected) => {
      if (result !== expected) {
        throw new Error(`${result} 與預期的 ${expected} 不符!`)
      }
    }
  }
}

Ruby的測試框架

在Ruby中,內建有「minitest」測試框架。特點是速度快,但難寫。另一個測試框架「RSpec」比較主流,須額外安裝,執行慢但語法易懂。

撰寫完畢的測試檔,以指令「rspec 測試檔名稱.rb」執行即可。

Ruby的測試實例

本文以ATM取/存款功能為例,設定測試條件及效果如下:
存錢功能

  • 可以存錢
  • 不可以存 0 元或是小於 0 元的金額(越存錢越少!)

領錢功能

  • 可以領錢
  • 不能領 0 元或是小於 0 元的金額(越領錢越多!)
  • 不能領超過本身餘額
class ATM
  def initialize(balance)
    @balance = balance #初始化進實體變數
  end

  def withdraw(money)
    if money > 0 and money <= @balance
      @balance = @balance - money
    return money
    else
      return 0 #領錢小於0的話 不給領錢
    end
  end

  def deposit(money)
    @balance = @balance + money if money > 0
  end

  def balance
    @balance #剩下就是餘額
  end
end

RSpec.describe ATM do
  context"領錢功能" do
    it "可以領錢" do
      atm = ATM.new(10)
      atm.withdraw(10)
      expect(atm.balance).to be 0
    end

    it "不能領0元" do
      atm = ATM.new(10)
      atm.withdraw(-50)
      expect(atm.balance).to be 10
    end

    it "不能領超過餘額" do
      atm = ATM.new(20)
      money = atm.withdraw(30)
      
      expect(atm.balance).to be 20
      expect(money).to be 0
    end
  end

  context"存錢功能" do
    it "可以存錢" do
      atm = ATM.new(10)
      atm.deposit(20)
      expect(atm.balance).to be 30 #(be(30)) 這是matcher
    end
  end

  context"存錢功能的限制" do
    it "不可存0元以下數額" do
      atm = ATM.new(10)
      atm.deposit(-20)
      expect(atm.balance).to be 10 #判斷餘額是否10元
    end
  end
end

上一篇
Day-26 事件機制(2)
下一篇
Day-28 特集:例外處理與FP
系列文
追憶JS年華30

尚未有邦友留言

立即登入留言