[Unit Test] 1.3 - 如何做好測試? - 可信任篇
在我看完單元測試的藝術和其他一些測試相關的資料後,我覺得如果要讓測試可信任,就應該具備以下 2 點:
- 可讀的,我能清楚測試撰寫者的意圖
- 此測試在該成功時成功,並且在該失敗時失敗
而要如何驗證可信任度呢? 還有如何加強或修正可信任度呢?
我們下面就會來介紹**「驗證可信任度的方法」和「修復可信任度的指導原則」**
驗證「可信任度」的流程
那如果要驗證我們的測試是否具有上述特性,要怎麼做呢?
如果你加了一個新測試,這裡有一套完整的流程供大家檢驗你的新測試:
- 註解掉你認為這段測試所涵蓋的那一段產品程式碼
- 執行所你的測試
- 檢驗結果:新測試是否失敗? 如果測試失敗了,那你的測試已經 50% 可信,如果測試通過了,表示你的測試根本沒有做到保護的本分,不然的話,你的測試應該會因此而失敗
- 尋找為什麼沒有失敗的原因,修正他,直到測試正常的失敗
- 移除之前的註解
- 檢驗結果:新測試是否成功? 新測試現在應該已經通過! 如果通過,恭喜你,不用看下一點了!
- 如果沒有,代表你測試了錯誤的東西,那就持續修正你的測試,直到通過,同時也要再回去測試註解產品程式碼註解時,還是要失敗。在該成功時成功,該失敗時失敗,才代表你的測試完成了
雖然步驟很多,但其實做起來很快,如果我們只針對一個測試反覆驗證 花費最多的時間只會是在思考
- 為什麼該成功時沒有成功
- 為什麼該失敗時沒有失敗
以下我會以一個限制字數上限的 input 為例
// nameInput.jsx
export const idNameInput = 'inputName';
export const nameLengthLimit = 100;
const NameInput = function NameInput(props) {
const { defaultName } = props;
const [inputVal, setInputVal] = useState(defaultName);
const handleInputVal = useCallback((e) => {
if (e.target.value.length > nameLengthLimit) {
return;
}
setInputVal(e.target.value);
}, [onChangeCampaignName]);
return (
<Flex flexDirection="column" alignItems="flex-end">
<Box display="inline-flex" alignItems="center">
<Text width={labelWidth}>
Name:
</Text>
<Input
data-track={idNameInput}
value={inputVal}
onChange={handleInputVal}
error={!inputVal}
/>
</Box>
<Text>
{inputVal.length} / {nameLengthLimit}
</Text>
</Flex>
);
}
export default NameInput;
// nameInput.test.tsx
import { fireEvent, render } from "@testing-library/react";
import NameInput, { nameLengthLimit, idNameInput } from "./_nameInput";
describe('NameInput', () => {
test('when typing on input which is already at its name length limit,
should keep same input value',
() => {
// Arrange
// 隨便使用一個英文字
const trivialChar = 'a';
// 用上面的英文字製造字串,重複數量到 name input 的上限字數
const maxString = trivialChar.repeat(nameLengthLimit);
// Act
const { getByTestId } = render(<NameInput defaultName={underLimitString} />);
const input = getByTestId(idNameInput);
// 宣告一個 name 長度極限(100) + 1 個 'a' 的字串
const newString = maxString + trivialChar;
// 傳到 input 中
fireEvent.change(input, { target: { value: newString }});
// Assert
// 應該要是 name 長度極限 (100) 個 'a' 的字串
expect(input).toHaveValue(maxString);
});
1st. 註解掉你認為這段測試所涵蓋的那一段產品程式碼
我們先把限制 input 輸入更多值的判斷是給註解掉,來看看是不是就真的不會被擋住了
const handleInputVal = useCallback((e) => {
// if (e.target.value.length > nameLengthLimit) {
// return;
// }
setInputVal(e.target.value);
}, [onChangeCampaignName]);