日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

三個要點,掌握Spring Boot單元測試

來源: 責編: 時間:2023-09-28 10:06:01 294觀看
導讀單元測試是軟件開發中不可或缺的重要環節,它用于驗證軟件中最小可測試單元的準確性。結合運用Spring Boot、JUnit、Mockito和分層架構,開發人員可以更便捷地編寫可靠、可測試且高質量的單元測試代碼,確保軟件的正確性和

單元測試是軟件開發中不可或缺的重要環節,它用于驗證軟件中最小可測試單元的準確性。結合運用Spring Boot、JUnit、Mockito和分層架構,開發人員可以更便捷地編寫可靠、可測試且高質量的單元測試代碼,確保軟件的正確性和質量。a8B28資訊網——每日最新資訊28at.com

a8B28資訊網——每日最新資訊28at.com

一、介紹

本文將從與單元測試相關的技術主題開始,在技術部分之后,介紹使用Spring Boot、JUnit和Mockito進行單元測試的實踐。a8B28資訊網——每日最新資訊28at.com

二、測試的關鍵要素

1.單元

單元測試中的單元一詞指的是軟件中可以單獨測試和處理的最小功能部分,通常是指函數、方法、類或模塊等獨立的代碼片段。a8B28資訊網——每日最新資訊28at.com

2.用例

用例描述了系統使用特定功能或特性的方式,用于理解、設計和測試軟件系統的需求。通常包括用戶如何與系統進行交互、對系統的期望以及應該實現的結果等詳細信息。a8B28資訊網——每日最新資訊28at.com

3.邊界情況

邊界情況指的是軟件必須處理的特定場景,這些場景包括意外或邊界條件,與典型情況有所不同或被認為是罕見的情況。邊界情況可以包括意外用戶登錄、測試限制、異常輸入或其他可能導致系統錯誤或異常行為的情況。在測試過程中,考慮和測試邊界情況是非常重要的,因為它們可以幫助開發人員發現潛在的問題并確保系統的魯棒性和穩定性。a8B28資訊網——每日最新資訊28at.com

三、單元測試

單元測試涵蓋了我們可以考慮并編寫的所有可能性。每個單元必須至少有一個測試方法。測試不是為一個方法編寫的,而是為一個單元編寫的。a8B28資訊網——每日最新資訊28at.com

可以按照以下順序編寫單元測試:正常路徑/用例、邊界情況和異常情況。a8B28資訊網——每日最新資訊28at.com

這些步驟是必不可少的,這樣做可以確保單元以正確的方式處理輸入,并生成預期的輸出,展現出預期的行為。單元測試是及早發現風險和修復錯誤的最佳方式。通過單元測試,我們可以預防潛在的意外情況,應對生產代碼的變更,確保生產代碼能夠處理各種情況。簡而言之,單元測試確保了生產代碼的安全性。a8B28資訊網——每日最新資訊28at.com

關于單元測試的另一個重要事項是要測試業務邏輯,不是在單元測試中測試基礎設施代碼,基礎設施代碼可以在集成測試中進行測試??梢钥紤]使用一些架構模式(如洋蔥架構、六邊形架構等)來將業務邏輯與基礎設施代碼分離。a8B28資訊網——每日最新資訊28at.com

單元測試的另一個優點是速度快,因為它不需要依賴 Spring ApplicationContext。由于上下文的原因,與單元測試相比,同一測試金字塔中的集成測試速度要慢得多。a8B28資訊網——每日最新資訊28at.com

1.開始編碼

在分層架構項目中,業務代碼主要位于服務層。這意味著服務層具有單元,需要進行測試。讓我們聚焦于最關鍵的部分。a8B28資訊網——每日最新資訊28at.com

以下是一段示例代碼:a8B28資訊網——每日最新資訊28at.com

  @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);    }

上述代碼中有兩個公共方法和一個私有方法,私有方法可以被視為公共方法的一部分。此外,由于代碼的復雜性和功能需求,還存在許多可能的場景需要編寫多個測試用例來覆蓋各種情況,以確保代碼的正確性。a8B28資訊網——每日最新資訊28at.com

2.注解

@ExtendWith用于將Mockito庫集成到JUnit測試中。@Test 標記一個方法,使其成為一個測試方法,測試方法包含指定的測試用例,并由 JUnit 自動運行。a8B28資訊網——每日最新資訊28at.com

在測試過程中,需要模擬正在測試的類的依賴項。之前提到的原因是,由于 Spring ApplicationContext 不會啟動,我們無法將依賴項注入到上下文中。@Mock 用于創建一個模擬的依賴項,而 @InjectMocks 則用于將這些模擬的依賴項注入到被測試類中。a8B28資訊網——每日最新資訊28at.com

@BeforeEach和@AfterEach可用于在每個方法運行之前和之后執行相應的操作。a8B28資訊網——每日最新資訊28at.com

@ParameterizedTest 用于使用不同的參數值運行重復的測試用例。通過使用 @ValueSource,可以為方法提供不同的參數值,以便進行多次測試。a8B28資訊網——每日最新資訊28at.com

3.測試方法的三個主要階段

  • Given: 準備測試用例所需的對象
  • When: 執行必要的操作以運行測試場景
  • Then: 檢查或驗證預期結果

doReturn/when 用于確定在給定指定參數時方法的行為方式。但是,由于依賴項是 @Mock,并不會真正執行。a8B28資訊網——每日最新資訊28at.com

verify 用于檢查被測試代碼是否按照預期行為執行。如果要測試的方法是 public void 類型,可以使用 verify 進行驗證。a8B28資訊網——每日最新資訊28at.com

斷言用于驗證預期結果。a8B28資訊網——每日最新資訊28at.com

 @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測試類運行時長為1秒693毫秒。a8B28資訊網——每日最新資訊28at.com

a8B28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-11820-0.html三個要點,掌握Spring Boot單元測試

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: DevOps優秀實踐之用戶與權限

下一篇: C 語言程序是如何在計算機內部工作?

標簽:
  • 熱門焦點
  • K6:面向開發人員的現代負載測試工具

    K6 是一個開源負載測試工具,可以輕松編寫、運行和分析性能測試。它建立在 Go 和 JavaScript 之上,它被設計為功能強大、可擴展且易于使用。k6 可用于測試各種應用程序,包括 Web
  • 如何正確使用:Has和:Nth-Last-Child

    我們可以用CSS檢查,以了解一組元素的數量是否小于或等于一個數字。例如,一個擁有三個或更多子項的grid。你可能會想,為什么需要這樣做呢?在某些情況下,一個組件或一個布局可能會
  • 得物效率前端微應用推進過程與思考

    一、背景效率工程隨著業務的發展,組織規模的擴大,越來越多的企業開始意識到協作效率對于企業團隊的重要性,甚至是決定其在某個行業競爭中突圍的關鍵,是企業長久生存的根本。得物
  • 深度探索 Elasticsearch 8.X:function_score 參數解讀與實戰案例分析

    在 Elasticsearch 中,function_score 可以讓我們在查詢的同時對搜索結果進行自定義評分。function_score 提供了一系列的參數和函數讓我們可以根據需求靈活地進行設置。近期
  • 阿里瓴羊One推出背后,零售企業迎數字化新解

    作者:劉曠近年來隨著數字經濟的高速發展,各式各樣的SaaS應用服務更是層出不窮,但本質上SaaS大多局限于單一業務流層面,對用戶核心關切的增長問題等則沒有提供更好的解法。在Saa
  • 網紅炒股不為了賺錢,那就是耍流氓!

    來源:首席商業評論6月26日高調宣布入市,網絡名嘴大v胡錫進居然進軍了股市。在一次財經媒體峰會上,幾個財經圈媒體大佬就&ldquo;胡錫進炒股是否知道認真報道&rdquo;展開討論。有
  • 蘋果公司要求三星和LG Display生產「無邊框」OLED iPhone顯示屏

    據 The Elec 報道,蘋果已要求其供應商為未來的 iPhone 型號開發「無邊框」OLED 顯示面板。蘋果顯然已要求三星和 LG Display 開發新的 OLED 顯示面
  • 回歸OPPO兩年,一加贏了銷量,輸了品牌

    成為OPPO旗下主打性能的先鋒品牌后,一加屢創佳績。今年618期間,一加手機全渠道銷量同比增長362%,憑借一加 11、一加 Ace 2、一加 Ace 2V三款爆品,一加
  • SN570 NVMe SSD固態硬盤 價格與性能兼具

    SN570 NVMe SSD固態硬盤是西部數據發布的最新一代WD Blue系列的固態硬盤,不僅閃存技術更為精進,性能也得到了進一步的躍升。WD Blue SN570 NVMe SSD的包裝外
Top 主站蜘蛛池模板: 开阳县| 镇雄县| 禹州市| 桃园市| 梨树县| 曲水县| 海兴县| 卢氏县| 大悟县| 会泽县| 敦煌市| 宁国市| 临朐县| 封丘县| 清流县| 东海县| 巴彦淖尔市| 海淀区| 武乡县| 宁陕县| 若尔盖县| 无锡市| 志丹县| 光泽县| 竹北市| 镇平县| 来宾市| 华坪县| 应用必备| 潜江市| 台湾省| 江阴市| 望奎县| 湘乡市| 衡南县| 乌兰浩特市| 郎溪县| 中超| 博野县| 图木舒克市| 右玉县|