偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

三個(gè)要點(diǎn),掌握Spring Boot單元測(cè)試

開發(fā) 測(cè)試
本文將從與單元測(cè)試相關(guān)的技術(shù)主題開始,在技術(shù)部分之后,介紹使用Spring Boot、JUnit和Mockito進(jìn)行單元測(cè)試的實(shí)踐。

單元測(cè)試是軟件開發(fā)中不可或缺的重要環(huán)節(jié),它用于驗(yàn)證軟件中最小可測(cè)試單元的準(zhǔn)確性。結(jié)合運(yùn)用Spring Boot、JUnit、Mockito和分層架構(gòu),開發(fā)人員可以更便捷地編寫可靠、可測(cè)試且高質(zhì)量的單元測(cè)試代碼,確保軟件的正確性和質(zhì)量。

一、介紹

本文將從與單元測(cè)試相關(guān)的技術(shù)主題開始,在技術(shù)部分之后,介紹使用Spring Boot、JUnit和Mockito進(jìn)行單元測(cè)試的實(shí)踐。

二、測(cè)試的關(guān)鍵要素

1.單元

單元測(cè)試中的單元一詞指的是軟件中可以單獨(dú)測(cè)試和處理的最小功能部分,通常是指函數(shù)、方法、類或模塊等獨(dú)立的代碼片段。

2.用例

用例描述了系統(tǒng)使用特定功能或特性的方式,用于理解、設(shè)計(jì)和測(cè)試軟件系統(tǒng)的需求。通常包括用戶如何與系統(tǒng)進(jìn)行交互、對(duì)系統(tǒng)的期望以及應(yīng)該實(shí)現(xiàn)的結(jié)果等詳細(xì)信息。

3.邊界情況

邊界情況指的是軟件必須處理的特定場(chǎng)景,這些場(chǎng)景包括意外或邊界條件,與典型情況有所不同或被認(rèn)為是罕見的情況。邊界情況可以包括意外用戶登錄、測(cè)試限制、異常輸入或其他可能導(dǎo)致系統(tǒng)錯(cuò)誤或異常行為的情況。在測(cè)試過程中,考慮和測(cè)試邊界情況是非常重要的,因?yàn)樗鼈兛梢詭椭_發(fā)人員發(fā)現(xiàn)潛在的問題并確保系統(tǒng)的魯棒性和穩(wěn)定性。

三、單元測(cè)試

單元測(cè)試涵蓋了我們可以考慮并編寫的所有可能性。每個(gè)單元必須至少有一個(gè)測(cè)試方法。測(cè)試不是為一個(gè)方法編寫的,而是為一個(gè)單元編寫的。

可以按照以下順序編寫單元測(cè)試:正常路徑/用例、邊界情況和異常情況。

這些步驟是必不可少的,這樣做可以確保單元以正確的方式處理輸入,并生成預(yù)期的輸出,展現(xiàn)出預(yù)期的行為。單元測(cè)試是及早發(fā)現(xiàn)風(fēng)險(xiǎn)和修復(fù)錯(cuò)誤的最佳方式。通過單元測(cè)試,我們可以預(yù)防潛在的意外情況,應(yīng)對(duì)生產(chǎn)代碼的變更,確保生產(chǎn)代碼能夠處理各種情況。簡(jiǎn)而言之,單元測(cè)試確保了生產(chǎn)代碼的安全性。

關(guān)于單元測(cè)試的另一個(gè)重要事項(xiàng)是要測(cè)試業(yè)務(wù)邏輯,不是在單元測(cè)試中測(cè)試基礎(chǔ)設(shè)施代碼,基礎(chǔ)設(shè)施代碼可以在集成測(cè)試中進(jìn)行測(cè)試??梢钥紤]使用一些架構(gòu)模式(如洋蔥架構(gòu)、六邊形架構(gòu)等)來將業(yè)務(wù)邏輯與基礎(chǔ)設(shè)施代碼分離。

單元測(cè)試的另一個(gè)優(yōu)點(diǎn)是速度快,因?yàn)樗恍枰蕾?Spring ApplicationContext。由于上下文的原因,與單元測(cè)試相比,同一測(cè)試金字塔中的集成測(cè)試速度要慢得多。

1.開始編碼

在分層架構(gòu)項(xiàng)目中,業(yè)務(wù)代碼主要位于服務(wù)層。這意味著服務(wù)層具有單元,需要進(jìn)行測(cè)試。讓我們聚焦于最關(guān)鍵的部分。

以下是一段示例代碼:

  @Override
    public String saveUser(User user) {
        validateUser(user);
        try {
            User savedUser = userRepository.save(user);
            return savedUser.getEmail();
        } catch (Exception exception) {
            throw new IllegalArgumentException(E_GENERAL_SYSTEM);
        }
    }

    private void validateUser(User user) {
        if (Objects.isNull(user.getEmail())) {
            throw new IllegalArgumentException(E_USER_EMAIL_MUST_NOT_BE_NULL);
        }
        if (findByEmail(user.getEmail()).isPresent()) {
            throw new IllegalArgumentException(E_USER_ALREADY_REGISTERED);
        }
    }

    @Override
    public Optional<User> findByEmail(String email) {
        return userRepository.findByEmail(email);
    }

上述代碼中有兩個(gè)公共方法和一個(gè)私有方法,私有方法可以被視為公共方法的一部分。此外,由于代碼的復(fù)雜性和功能需求,還存在許多可能的場(chǎng)景需要編寫多個(gè)測(cè)試用例來覆蓋各種情況,以確保代碼的正確性。

2.注解

@ExtendWith用于將Mockito庫集成到JUnit測(cè)試中。@Test 標(biāo)記一個(gè)方法,使其成為一個(gè)測(cè)試方法,測(cè)試方法包含指定的測(cè)試用例,并由 JUnit 自動(dòng)運(yùn)行。

在測(cè)試過程中,需要模擬正在測(cè)試的類的依賴項(xiàng)。之前提到的原因是,由于 Spring ApplicationContext 不會(huì)啟動(dòng),我們無法將依賴項(xiàng)注入到上下文中。@Mock 用于創(chuàng)建一個(gè)模擬的依賴項(xiàng),而 @InjectMocks 則用于將這些模擬的依賴項(xiàng)注入到被測(cè)試類中。

@BeforeEach和@AfterEach可用于在每個(gè)方法運(yùn)行之前和之后執(zhí)行相應(yīng)的操作。

@ParameterizedTest 用于使用不同的參數(shù)值運(yùn)行重復(fù)的測(cè)試用例。通過使用 @ValueSource,可以為方法提供不同的參數(shù)值,以便進(jìn)行多次測(cè)試。

3.測(cè)試方法的三個(gè)主要階段

  • Given: 準(zhǔn)備測(cè)試用例所需的對(duì)象
  • When: 執(zhí)行必要的操作以運(yùn)行測(cè)試場(chǎng)景
  • Then: 檢查或驗(yàn)證預(yù)期結(jié)果

doReturn/when 用于確定在給定指定參數(shù)時(shí)方法的行為方式。但是,由于依賴項(xiàng)是 @Mock,并不會(huì)真正執(zhí)行。

verify 用于檢查被測(cè)試代碼是否按照預(yù)期行為執(zhí)行。如果要測(cè)試的方法是 public void 類型,可以使用 verify 進(jìn)行驗(yàn)證。

斷言用于驗(yàn)證預(yù)期結(jié)果。

 @ExtendWith(MockitoExtension.class)
class UserServiceImplTest {

    @InjectMocks
    private UserServiceImpl userService;

    @Mock
    private UserRepository userRepository;

    private User user;
    public static final String MOCK_EMAIL = "mert@bahardogan.com";

    @BeforeEach
    void setUp() {
        user = new User();
        System.out.println("init");
    }

    @AfterEach
    void teardown() {
        System.out.println("teardown");
    }

    @ParameterizedTest
    @ValueSource(strings = {"mert@bahardogan.com", "info@gmail.com"})
    @DisplayName("Happy Path: save user use cases")
    void givenCorrectUser_whenSaveUser_thenReturnUserEmail(String email) {
        // given
        user.setUserName("mertbahardogan").setEmail(email).setPassword("pass");
        User savedUser = new User().setEmail(email);
        doReturn(savedUser).when(userRepository).save(any());

        // when
        String savedUserEmail = userService.saveUser(user);

        // then
        verify(userRepository,times(1)).findByEmail(anyString());
        verify(userRepository,times(1)).save(any());
        assertEquals(email, savedUserEmail);
    }

    @Test
    @DisplayName("Exception Test: user email must not be null case")
    void givenNullUserEmail_whenSaveUser_thenThrowsEmailMustNotNullEx() {
        // when
        Exception exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));

        // then
        assertNotNull(exception);
        assertEquals(E_USER_EMAIL_MUST_NOT_BE_NULL, exception.getMessage());
    }

    @Test
    @DisplayName("Exception Test: user is already registered case")
    void givenRegisteredUser_whenSaveUser_thenThrowsUserAlreadyRegisteredEx() {
        // given
        user.setEmail(MOCK_EMAIL);
        Optional<User> savedUser = Optional.of(new User().setEmail(MOCK_EMAIL));
        doReturn(savedUser).when(userRepository).findByEmail(anyString());

        // when
        Exception exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));

        // then
        assertNotNull(exception);
        assertEquals(E_USER_ALREADY_REGISTERED, exception.getMessage());
    }

    @Test
    @DisplayName("Exception Test: catch case")
    void givenIncorrectDependencies_whenSaveUser_thenThrowsGeneralSystemEx() {
        // given
        user.setEmail(MOCK_EMAIL);

        // when
        Exception exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));

        // then
        assertNotNull(exception);
        assertEquals(E_GENERAL_SYSTEM, exception.getMessage());
    }

    @Test
    @DisplayName("Happy Path: find user by email")
    void givenCorrectUser_whenFindByEmail_thenReturnUserEmail() {
        // given
        Optional<User> savedUser = Optional.of(new User().setEmail(MOCK_EMAIL));
        doReturn(savedUser).when(userRepository).findByEmail(anyString());

        // when
        Optional<User> user = userService.findByEmail(MOCK_EMAIL);

        // then
        verify(userRepository,times(1)).findByEmail(anyString());
        assertEquals(savedUser, user);
    }
}

UserServiceImpl測(cè)試類運(yùn)行時(shí)長(zhǎng)為1秒693毫秒。

責(zé)任編輯:趙寧寧 來源: Java學(xué)研大本營(yíng)
相關(guān)推薦

2021-09-01 12:03:49

Spring單元測(cè)試

2017-01-16 12:12:29

單元測(cè)試JUnit

2017-01-14 23:26:17

單元測(cè)試JUnit測(cè)試

2025-06-12 03:10:00

2021-01-07 14:06:30

Spring BootJUnit5Java

2013-06-04 09:49:04

Spring單元測(cè)試軟件測(cè)試

2017-01-14 23:42:49

單元測(cè)試框架軟件測(cè)試

2021-08-26 11:00:54

Spring BootJUnit5Java

2015-09-28 15:03:38

網(wǎng)絡(luò)架構(gòu)測(cè)試

2024-10-16 16:09:32

2020-08-18 08:10:02

單元測(cè)試Java

2024-05-17 09:46:17

Python單元測(cè)試unittest模塊

2023-09-01 07:15:58

UnittestPython

2020-07-21 14:40:45

Spring Boot單元測(cè)試Java

2014-02-25 10:25:52

單元測(cè)試測(cè)試

2021-09-27 13:02:05

Python技巧測(cè)試

2017-03-23 16:02:10

Mock技術(shù)單元測(cè)試

2021-05-05 11:38:40

TestNGPowerMock單元測(cè)試

2021-04-23 07:33:10

SpringSecurity單元

2023-07-26 08:58:45

Golang單元測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)