iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0
Modern Web

與 AI 一起開發 Side Project 吧!系列 第 20

Day20 — 穩如泰山 | 急速產單元測試 Part2,優化指令產出更好的測試!

  • 分享至 

  • xImage
  •  

上一次我們只調整了一個測試,花上了不少時間,因為還在摸索如何調整。畢竟萬事起頭難,第一次總是最讓人勸退。

不過有了上次經驗之後,再調整第二個、第三個…,應該會快上不少,有了整理過的測試,還有流程可以做參考,想必會快上許多吧!

測試也要優化

測試也要易讀好懂

標準的測試「模板」,上次已經藉由 BDD 整理好了,再為大家複習一下,大概長這樣:

 it('adds new item to history when category is selected and confirms', () => {
  whenRender()

  whenInputNumber(10);
  whenClickOK();
  
  whenSelectCategory('飲食');
  whenClickOK();
  
  thenCategoryShouldHave('飲食');
  thenAmountShouldBe('$10');
});

由 when(行為) 和 then(預期)兩大部分所組成,比較像是人類講的白話文,而不是程式實作細節那般文謅謅。那試著下指令告訴 AI,參考這個「模板」,把另一個測試也調整看看囉。

先調整這個測試:

it('deletes item from history when delete button is clicked', async () => {
  render(<App />);
  fireEvent.click(screen.getByText('1'));
  fireEvent.click(screen.getByText('0'));
  fireEvent.click(screen.getByText('OK'));
  
  fireEvent.click(screen.getByText('飲食'));
  fireEvent.click(screen.getByText('OK'));
  
  const deleteButton = screen.getByText('刪除');
  fireEvent.click(deleteButton);
  
  expect(screen.queryByText('飲食')).not.toBeInTheDocument();
  expect(screen.queryByText('$10')).not.toBeInTheDocument();
});

給 AI 以下指令,請他幫我照著之前寫過的測試來重構:

請參考此檔案中的 adds new item to history when category is selected and confirms BDD 寫法,重構 deletes item from history when delete button is clicked 這個測試

看了生成的結果, AI 確實有幫我把「已經有 function 的地方」做了重構,但其他沒提到的,就沒有做 ,還真是老實 😂

所以還要補充一下 follow up 指令

另外,「刪除項目」這部分抽成方法,驗證「已被刪除」也抽成方法

最後終於好了,該抽的方法有幫我抽起來

//...

function whenDeleteItem() {
  const deleteButton = screen.getByText('刪除');
  fireEvent.click(deleteButton);
}

function thenItemShouldBeDeleted(item: string, amount: string) {
  expect(screen.queryByText(item)).not.toBeInTheDocument();
  expect(screen.queryByText(amount)).not.toBeInTheDocument();
}

it('deletes item from history when delete button is clicked', async () => {
  whenRender();

  whenInputNumber(10);
  whenClickOK();
  
  whenSelectCategory('飲食');
  whenClickOK();
  
  thenCategoryShouldHave('飲食');
  thenAmountShouldBe('$10');

  whenDeleteItem();
  
  thenItemShouldBeDeleted('飲食', '$10');
});

一次重構全部測試,辦得到嗎?

有了兩個很像,但又不太一樣的測試,AI 應該可以參考寫法,幫我重構得很好吧? 於是乎,選擇了 claude-3.5-sonnet 模型,並提供以下指令:

請幫我依照 'adds new item to history when category is selected and confirms' 和 'deletes item from history when delete button is clicked' 的寫法(BDD 開發),
將其他「所有測試」都重構成如此寫法,謝謝

眨眼間的功夫,幫我把整份測試都重構了一輪,也很貼心地幫我調整了 function 的順序 🥺

function whenRender() {
  render(<App />);
}

function whenInputNumber(number: number) {
  number.toString().split('').forEach(digit => {
    fireEvent.click(screen.getByText(digit));
  });
}

//...

describe('AccountingApp', () => {
  it('renders two components with total amount as $0', () => {
    whenRender();
    thenAmountShouldBe('$0');
  });

  it('allows input of numbers and updates the display', () => {
    whenRender();
    whenInputNumber(123);
    thenElementShouldExist('$123');
  });

  it('clears the input when AC button is clicked', () => {
    whenRender();
    whenInputNumber(12);
    whenClickButton('AC');
    thenAmountShouldBe('$0');
  });

  it('removes last digit when backspace button is clicked', () => {
    whenRender();
    whenInputNumber(123);
    whenClickButton('⌫');
    thenElementShouldExist('$12');
  });
  
  //...

就此,重構差不多可以算大功告成了,如果還想要做得更好,是可以將相關的邏輯,以空行隔開,像是如下所示,這樣會更清楚一點喔。

// before
it('adds new item to history when category is selected and confirms', () => {
  whenRender();
  whenInputNumber(10);
  whenClickOK();
  whenSelectCategory('飲食');
  whenClickOK();
  thenCategoryShouldHave('飲食');
  thenAmountShouldBe('$10');
});

// after
it('adds new item to history when category is selected and confirms', () => {
  whenRender();
  
  whenInputNumber(10);
  whenClickOK();
  
  whenSelectCategory('飲食');
  whenClickOK();
  
  thenCategoryShouldHave('飲食');
  thenAmountShouldBe('$10');
});

結語

由下而上做重構

這次演示的測試重構,是由下而上做重構。是等具體的測試實作都寫好之後,再來把類似或重複的邏輯做整理,將測試重構得更好理解,結構變得更簡潔。將最具體的測試細節,重構為抽象的概念測試行為。

下次要介紹給大家的是另外一個寫法,試試看「由上而下」來寫測試,先寫抽象的概念測試行為,再來才是把具體的測試細節給補上。


上一篇
Day19 — 穩如泰山 | 測試也是需要整理維護的,跟 AI 一起整理測試
下一篇
Day21 — 穩如泰山 | 測試換個寫法試試看? AI 協助下的新寫法嘗試
系列文
與 AI 一起開發 Side Project 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言