目前在廣泛的原因有這幾種:
- 確保程式碼的正確性
- 提高開發速度
- 可當成是一種「文件」紀錄
- 提高程式碼的維護性、更容易除錯
其實關於第二點,我自己是比較難想像,我相信平常沒有寫測試的夥伴應該也很難認同XD
【圖】那些已經有在寫測試的人就會回嗆:你就是不寫測試才沒時間!
.
撇除這些看起來很高大尚的理由,比較吸引我想要研究/寫測試有幾個原因:
沒錯,就是這麼現實這麼實在XD
「寫測試」這件事情已經變成是一個指標,象徵著初階工程師與資深工程師的分水領。打開104人力銀行,70%以上資深工程師的Job Description都有這一條。
【圖】擷取自104上的資深前端工程師JD
總之,「寫測試」這件事情正好在風口上。如果你打算要換工作的話,學習寫測試會是比較有短期回報的投資。
.
這件事我蠻有感的。
像我是做人事系統的,這些表單的程式邏輯都是一個扣著一個,或是彼此的關聯度很高。
專案上線一兩年後,我早就忘了當初的規則。這時候需求單位想要加功能、改規則,我在開發的時候就比較會擔心會不會「改了這個地方,但壞了另一個地方」。
因此這兩天看到某位Youtuber分享寫測試有這個好處的時候,我就蠻有感的,也讓我會比較有意願去寫測試。
.
雖然這個原因有點「倒果為因」,卻也是寫測試帶來的好處。
沒寫過測試的沒有或許不知道,並不是每個函數都「能」測試。為了要寫出比較好寫測試的程式碼,你開始會簡化你的function,儘量讓它「一次只做一件事」。因此,在寫測試的同時,你也寫出了更好維護的程式碼。
.
.
.
(希望這麼爛的梗沒有人用過XD)
「測試」有三個種類,不同類型的測試,也代表著不同的「寫測試策略」,而且也會影響到你要選擇的測試框架。讓我們一起有哪三種測試!
簡單來說就是對「單一的函數」進行測試,測試的方式就是去檢查Input和Output的值是不是一致的、符合預期的。
單元測試是三種測試裡面最好寫的(因為它比較單純),也是在有限的時間下會最先投入的。
// ———————————————— 以下是ChatGPT給的範例,以登入為例 ————————————————
// 測試工具:Jest
function login(username, password) {
if (username === 'your_username' && password === 'your_password') {
return 'success';
} else {
return 'error';
}
}
describe('Login Function', () => {
it('should return "success" with valid credentials', () => {
const result = login('your_username', 'your_password');
expect(result).toBe('success');
});
it('should return "error" with invalid credentials', () => {
const result = login('invalid_username', 'invalid_password');
expect(result).toBe('error');
});
});
.
和單元測試這種偏向針對程式碼的測試方式不同,端對端測試是模擬User在瀏覽器的操作行為,針對不同情境跑出來的結果是否符合預期。
// ———————————————— 以下是ChatGPT給的範例,以登入為例 ————————————————
// 測試工具:Cypress
describe('Login Page', () => {
it('should be able to log in with valid credentials', () => {
cy.visit('/login'); // 前往登入頁面
cy.get('#username').type('your_username'); // 輸入用戶名
cy.get('#password').type('your_password'); // 輸入密碼
cy.get('#login-button').click(); // 點擊登入按鈕
cy.url().should('eq', '/dashboard'); // 驗證登入後 URL 是否為預期
});
it('should display an error message with invalid credentials', () => {
cy.visit('/login'); // 前往登入頁面
cy.get('#username').type('invalid_username'); // 輸入無效的用戶名
cy.get('#password').type('invalid_password'); // 輸入無效的密碼
cy.get('#login-button').click(); // 點擊登入按鈕
cy.get('#error-message').should('be.visible'); // 驗證錯誤消息是否可見
});
});
.
從上面兩種類型的測試,我們可以看到單元測試偏向測程式碼邏輯的正確性,端對端測試偏向從User的角度來進行測試。而所謂的「整合測試」就是兩者的結合,它從單元測試出發,但同時也會去測在不同情境下使用者在瀏覽器會看到的結果是否符合預期。
// ———————————————— 以下是ChatGPT給的範例,以登入為例 ————————————————
// 測試工具:cypress
describe('Login Integration Test', () => {
it('should log in successfully with valid credentials', () => {
cy.visit('/'); // 前往應用程式首頁
cy.get('#username').type('your_username'); // 輸入用戶名
cy.get('#password').type('your_password'); // 輸入密碼
cy.get('#login-button').click(); // 點擊登入按鈕
// 確認是否成功重定向到儀表板頁面
cy.url().should('eq', '/dashboard');
// 檢查儀表板頁面上的某些元素是否存在
cy.get('#welcome-message').should('be.visible');
cy.get('#user-avatar').should('be.visible');
});
it('should display an error message with invalid credentials', () => {
cy.visit('/'); // 前往應用程式首頁
cy.get('#username').type('invalid_username'); // 輸入無效的用戶名
cy.get('#password').type('invalid_password'); // 輸入無效的密碼
cy.get('#login-button').click(); // 點擊登入按鈕
// 確認是否顯示登入錯誤消息
cy.get('#error-message').should('be.visible');
});
});
.
.
.
時間的關係我直接截我用ChatGPT進行對談時,請它整理出來的表格。
就像我們之前聊到的,不同的測試工具它適用的測試類型不同,就像Jest是用來做單元測試、整合測試的,就沒有支援端對端測試。(當然,如果你硬是要拿Jest來做端對端測試也是可以,但要另外安裝許多東西,倒不如直接改用被定位用來做端對端測試的Cypress。)
另外,有些測試工具並不包含「測試運行器」,需要另外安裝。「測試運行器」有點像演員,它會按照你寫的腳本(測試程式碼),去模擬使用者在瀏覽器上操作,讓你看看這個「演出結果」是否如你預期。一般來說,能支援測試運行器的工具,通常也可以做端對端測試。
.
.
.
有誰OS跟我一樣XD