iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0
Software Development

Spring boot 從零到寫出ChatGPT系列 第 22

Spring boot 從零開始 (22) - 來撰寫Unit Test 之Mockito介紹

  • 分享至 

  • xImage
  •  

Hello👋 那我們就來延續昨天的分享,今天繼續介紹Mockito

(二) Mockito

主要是讓我們可以透過Mock的方式去建立類別,並且被注入,讓我們可以專心去寫單元測試,不用為了Bean的相依性而煩惱。

Mock 類別

@Mock :通常會標註在Repo物件上,模擬與資料庫連接的部分

@InjectMocks :如果今天要測試的service裡面有注入dependency classes,這時候我們就可以在此service上面標註

@MockBean : Mockito 會幫我們創建一個假的 mock 對象,替換掉已存在的那個真實的bean

Mock 行為

when : 測試function中,用來撰寫測試項目該執行的行為

thenReturn : 代表回傳的結果
thenThrows : 代表預期會拋出的例外

Assert 常用方法

assertNotNull : 驗證結果是否不為空值,如果為空會拋出例外

assertNull : 驗證結果為空值

assertEquals : 驗證預期與實際結果是否相等

assertThrows : 預期拋出 exception

我們在這邊用前面的IronService來寫測試當範例 👇

@Service
@Slf4j
public class IronService {
    @Autowired
    private BookRepo bookRepo;

    public Book findBookById(Integer id) throws BadRequestException {
        Book book = new Book();
        book = bookRepo.findBookByBookId(id);
        if(Objects.isNull(book.getBookId())) {
            throw new BadRequestException(String.format("Can not find bookId: %d",id ));
        } else {
            return book;
        }
    }
}    

我們先來寫一個用BookId查詢Book相關資訊的測試 👇

  1. 這邊我們透過@MockBean來讓Mockito幫我們把原本的BookRepo替換掉
  2. 一樣將原本的service注入
  3. 開始依照原本的邏輯寫一個測試
  4. 我們透過when來撰寫測試行為,所以 when(bookRepo.findBookByBookId(1)).thenReturn(book1);代表我們利用BookId查詢Book物件,thenReturn就代表回傳的結果
  5. 接著我們就實際執行要測試的service.{method}
  6. assertNotNull : 代表我們預期結果不為空值
  7. assertEquals : 判斷預期跟實際的結果是否相符
@RunWith(SpringRunner.class)
@SpringBootTest
public class IronServiceTest {
    @MockBean
    private BookRepo bookRepo;
    @Autowired
    private IronService mockIronService;


    @Test
    public void testGetBookById() throws BadRequestException {
        Book book1 = new Book();
        book1.setBookId(1);
        book1.setName("Hello World");
        book1.setAuthor("Winnie");
        when(bookRepo.findBookByBookId(1)).thenReturn(book1);

        mockIronService.findBookById(1);
        assertNotNull(book1);
        assertEquals(book1.getBookId(), 1);
        assertEquals(book1.getName(), "Hello World");
    }
}    

接著寫一個用查詢不到Book相關資訊的測試 👇

  1. 這邊主要會用到 assertThrows 來預期我們要丟出的例外
  2. 接著再用assertEquals去比對我們Exception message是否跟我們預期的相同
    @Test
    public void testGetBookByIdNotFound() throws BadRequestException {
        Book book1 = new Book();
        when(bookRepo.findBookByBookId(1)).thenReturn(book1);

        BadRequestException exception = assertThrows(BadRequestException.class, () -> {
            mockIronService.findBookById(1);
        });
        assertEquals(String.format("Can not find bookId: %d",1), exception.getMessage());
    }

我們就可以來試試看執行我們寫的測試,是否順利通過 ~
執行結果 :
https://ithelp.ithome.com.tw/upload/images/20241006/20112118ZiEhdrk2Gg.png

我們也可以用昨天跟大家分享的coverage執行看看,接著點回去原本的IronService就可以看到以下畫面,
有綠色的話代表測試有覆蓋到,紅色的話就代表測試沒有覆蓋到
https://ithelp.ithome.com.tw/upload/images/20241006/20112118BuMiF3y32p.png

所以我們可以透過撰寫測試來驗證自己的程式邏輯是否正確以外,也可以看出我們把function是不是寫的過度複雜,所以平常要養成好習慣,一起守護我們的程式品質吧 /images/emoticon/emoticon08.gif

參考來源

JUnit 5 Expected Exception


上一篇
Spring boot 從零開始 (21) - 來撰寫Unit Test 之Junit介紹
下一篇
Spring boot 從零開始 (23) - Spring security 介紹 & 基本配置
系列文
Spring boot 從零到寫出ChatGPT30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言