iT邦幫忙

2023 iThome 鐵人賽

DAY 21
1
自我挑戰組

富士大顆系列 第 21

vol. 21 Rails 的「測試-測試-測試!」(上)

  • 分享至 

  • xImage
  •  

你好,我是富士大顆 Aiko
接下來會介紹關於 Rails 裡的測試,
這篇會講到:

  • 軟體開發為什麼要做測試?
  • 測試的種類
  • 常見的測試工具

真的不要以為躲得掉...
準備好了嗎?gogo!


軟體開發為什麼要做測試?

不僅可以提高產品品質,還可以加速開發速度,降低風險和成本,或是提供更好的 UX。

確保品質:

  1. 及早偵測錯誤和缺點:在測試環境搶先除錯跟改進。
  2. 驗證功能完整性
  3. 提高良率:良好的測試覆蓋率可以提高軟體的可靠性和穩定性。

提高開發效率:

  1. 快速更新:可以更有信心地進行代碼修改和重構,而不必擔心破壞現有功能。
  2. CI/CD:Continuous Integration, CI 自動化設定和測試,確保程式碼更改不會破壞現有功能/ Continue Delivery, CD,持續交付,自動化部署應用程式到指定環境,來提高速度。

降低維護成本:

  1. 減少人工測試:自動化測試可以大大減少人工測試的時間和成本。
  2. 文件即測試:測試碼本身就是一種很好的文件說明書,描述了軟體應有的行為和功能規範。

提升用戶體驗:

  1. 效能穩定:確保軟體在高負載或大數據量下仍能保持良好的響應速度和穩定性。
  2. 安全防漏:及早識別和修復安全漏洞,保護敏感資料。

符合法規和標準:

  1. 合規性測試:某些行業或市場有特定的軟體品質和安全標準,測試可以確保軟體符合這些標準。

測試的種類

1. 單元測試(Unit Testing)

單元測試主要針對程式中的最小可測試單元(通常是方法或函數)進行測試,unit 就是指最小組成單位。

** 測試 model user 裡的 full_name **

# app/models/user.rb
class User
  def full_name
    "#{first_name} #{last_name}"
  end
end

# test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "should return full name" do
    user = User.new(first_name: "Aiko", last_name: "Chen")
    assert_equal "Aiko Chen", user.full_name
  end
end

2. 功能測試(Functional Testing)

針對控制器 Controller 的各個 action 進行測試。

** 測試 controller users 的 index action **

# test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
  end
end

3. 整合測試(Integration Testing)

用於測試多個單位或系統之間的互動。

** 測試 navigation 是否會呈現(這個路徑可能多個地方會使用到)**

# test/integration/navigation_test.rb
require 'test_helper'

class NavigationTest < ActionDispatch::IntegrationTest
  test "can see the welcome page" do
    get "/"
    assert_select "h1", "Welcome"
  end
end

4. 端對端測試(End-to-End Testing)

模擬真實 user 行為,通常使用瀏覽器自動化工具。

** 使用 Capybara 進行端對端測試 **

# spec/features/user_visits_homepage_spec.rb
require 'spec_helper'

feature "User visits homepage" do
  scenario "successfully" do
    visit root_path
    expect(page).to have_content("Welcome")
  end
end

常見的瀏覽器自動化工具

  1. Selenium: 這是最受歡迎的瀏覽器自動化工具之一。它支援多種瀏覽器和程式語言,包括 Java、C#、Python 和 Ruby。

** Ruby 中使用 Selenium **

```ruby
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :firefox
driver.navigate.to "http://www.google.com"
element = driver.find_element(name: 'q')
element.send_keys "Hello Selenium"
element.submit
```
  1. Capybara: 通常與 RSpec 或 MiniTest 一起使用。

** Ruby 中使用 Capybara **

```ruby
visit '/login'
fill_in 'Username', with: 'user'
fill_in 'Password', with: 'password'
click_button 'Login'
```
  1. Puppeteer: 這是一個 Node 套件,提供了一組 API 來控制無頭版(headless)的 Chrome 或 Chromium。

** Javascript 中使用 Puppeteer **

```javascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({ path: 'example.png' });
  await browser.close();
})();
```
  1. TestCafe: 用於端對端網頁測試的 Node.js 工具,不需要 WebDriver(WebDriver 是 Selenium 專案的一部分,但也可以獨立使用)。

** Javascript 中使用 TestCafe **

```javascript
fixture `Getting Started`
    .page `http://devexpress.github.io/testcafe/example`;

test('My first test', async t => {
    await t
        .typeText('#developer-name', 'John Doe')
        .click('#submit-button');
});
```

常見測試工具

1. RSpec

RSpec 因其使用操作直覺(語感易懂)是 Ruby 社群中最受歡迎的測試框架之一。

安裝:

gem install rspec

** 測試 model user 裡的方法,是否會回傳 full name **

# app/models/user.rb
class User
  def full_name
    "#{first_name} #{last_name}"
  end
end

# spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  it "returns full name" do
    user = User.new(first_name: "Aiko", last_name: "Chen")
    expect(user.full_name).to eq("Aiko Chen")
  end
end

2. MiniTest

Rails 內建的,提供了一個輕量級的測試框架,使用語言較 Repec 不直覺。

** 測試 model user 裡的方法,是否會回傳 full name **

# app/models/user.rb
class User
  def full_name
    "#{first_name} #{last_name}"
  end
end

# test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "should return full name" do
    user = User.new(first_name: "Aiko", last_name: "Chen")
    assert_equal "Aiko Chen", user.full_name
  end
end

你可以直接用這兩個例子進行比較,是不是 Rspec 比較看得懂呢!

3. Capybara

用於模擬真實 user 與網頁互動的工具。

安裝:

gem install capybara

** 使用 Capybara 進行端對端測試 **

# spec/features/user_visits_homepage_spec.rb
require 'spec_helper'

feature "User visits homepage" do
  scenario "successfully" do
    visit root_path
    expect(page).to have_content("Welcome")
  end
end

4. FactoryBot

用於生成測試資料的套件。

安裝:

gem install factory_bot_rails

** 用 FactoryBot 新增假(for 測試)資料 **

# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    first_name { "Aiko" }
    last_name  { "Chen" }
  end
end

# spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  it "returns full name" do
    user = create(:user)
    expect(user.full_name).to eq("Aiko Chen")
  end
end

接下來會繼續談到:如何設定與執行測試環境、TDD
敬請期待我們明天見!


上一篇
vol. 20 Rails 裡的 Life Cycle & Callback
下一篇
vol. 22 Rails 的「測試-測試-測試!」:「環境」怎麼設定?(中)
系列文
富士大顆30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言