<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                本節我們處理兩個長度的校驗。在原型中我們規定了學號的長度必須是6位,而姓名則最短為2位,最長為20位。我們在上兩個小節中分別通過了@JoinColumn及@Column進行非null及unique設置,這是由于數據庫本身就是支持這樣的校驗的。 當我們對其進行null設置時,jpa會自動在數據表的對應字段上設置`不是null`屬性: ![](https://img.kancloud.cn/a5/8c/a58c8aa43282f92b389245ae8b2a1635_769x153.png) 當我們對其進行unique設置時,jpa會自動在數據表中為對應的字段添加UNIQUE類型的索引: ![](https://img.kancloud.cn/31/ba/31baf9653f4a9a83c16193536c604e71_1508x218.png) 但數據庫卻并不支持對某個字段設置其長度必須為多少位,或是其長度必須位于哪兩個值之間。所以此時@JoinColumn及@Column便解決不了這個問題了,這也是當我們查看@JoinColumn及@Column官方文檔時,并沒有找到對應的選項的原因。 > 這兩個注解中有一個length選項,但其官方的解釋為:(Optional) The column length. (Applies only if a string-valued column is used.) ,譯為:字段長度。該長度是指該字段所允許的最大長度,傳入的值只要不超過該值即可。但這并不是我們想要的。 為了處理這種問題,JPA為我們提供了@PrePersist注解,在數據正式被保存前,該注解下的方法將被觸發執行1次。 ## @PrePersist 我們在entity/Student.java中建立以下方法: ``` /** * 在實體保存到數據庫以前,執行1次 */ @PrePersist public void perPersis() { } ``` ### 補充代碼 繼續補充該方法中的代碼,完成name和sno的長度校驗。 ``` @Column(nullable = false) private String name; /** * 在實體保存到數據庫以前,執行1次 * 1. 校驗name 字段長度為2-20 * 2. 校驗sno 字段長為為6 */ @PrePersist public void perPersis() { if (this.name != null ) { ① if (this.name.length() < 2) { throw new DataIntegrityViolationException("name length less than 2"); ? } if (this.name.length() > 20) { throw new DataIntegrityViolationException("name length more than 20"); ? } } if (this.sno != null) { ② if (this.sno.length() != 6) { throw new DataIntegrityViolationException("sno length must be 6"); ? } } } ``` * ① 對name進行校驗 * ② 對sno進行校驗 * ? 拋出更通用的DataIntegrityViolationException異常,同時在異常中給出有指導意義的提示 ## 測試 姓名過短: ``` @Test(expected = DataIntegrityViolationException.class) public void nameLengthToShortTest() { this.student.setName("1"); this.studentRepository.save(student); } ``` 姓名過長: ``` @Test(expected = DataIntegrityViolationException.class) public void nameLengthToLongTest() { this.student.setName("123456789012345678901"); this.studentRepository.save(student); } ``` 學號長度非6位: ``` @Test(expected = DataIntegrityViolationException.class) public void snoLengthTest() { this.student.setSno("12345"); this.studentRepository.save(student); } ``` ### 增加測試樣本及細化測試 雖然使用@Test(expected = DataIntegrityViolationException.class)能夠快速的測試異常,但這種方法存在先天的不足,比如:每個測試用例只能測試一次異常。當我們需要進行多樣本測試的時候,它便顯得力不從心了。在剛剛測試中,我們每個測試用例中均使用了一個樣本。這為我們的后續更新造成了一定的風險。比如學號的長度由6位升級為8位,我們來在Student.java中,將6修改為8,卻發現原來的單元測試仍然被通過了。這是由于我們的單元測試的邏輯為:將學號為5位時,觸發異常。而無論學號的長度是6位還是8位,都會滿足長度不為5的單元測試。而正常的測試邏輯則應該是,我們使用多個長度的學號進行測試,僅當長度為6時不報錯。 所以:一個合格的測試應該長成這樣: ``` import org.assertj.core.internal.bytebuddy.utility.RandomString; @Test public void snoLengthTest() { for (int i = 1; i <= 255; i++) { ① this.student.setSno(RandomString.make(i)); ② boolean called = false; try { this.studentRepository.save(student); } catch (DataIntegrityViolationException e) { called = true; } if (i != 6) { Assertions.assertThat(called).isTrue(); ③ } else { Assertions.assertThat(called).isFalse(); ④ } this.before(); ⑤ } } ``` * ① 測試255次 * ② 獲取長度為i的字符串,并用此字符串來設置學號 * ③ 當字符串的長度為6時,斷言未發生異常 * ④ 當字符串的長度不為6時,斷言發生異常 * ⑤ 生成一個新學生 此時,如果我們將Student中的長度校驗由6改為其它長度時,則單元測試將無法通過。 **請自行完成name字段的長度校驗后繼續學習** ### 多測試用例間互相影響 至此我們完成了學生實體的校驗過程,我們大概寫了10來個單元測試。接下來我們做個奇怪的實驗:單獨運行任何一個單元測試均正常通過測試;但統一運行該測試文件的所有測試卻發生了錯誤: ![](https://img.kancloud.cn/1b/f9/1bf904a4e72bf68c1fbcd6ef5b63bce7_493x167.png) 失敗: ![](https://img.kancloud.cn/b7/92/b792824b2c95539453b2fe70a10c9e59_412x162.png) 這是由于對某個測試文件進行測試時相當于對該文件中的所有測試文件進行逐個測試,這就會面臨多個單元測試用例互相影響的問題。 * [ ] 只運行一個測試用例,該測試用例執行完畢后,JPA自動為我們刪除了數據庫;再運行另一個測試用例時,數據庫為空庫。兩個測試用例互不影響。 * [ ] 運行一個測試文件,該測試文件中的所有測試用例執行完畢后,此時JPA自動為我們刪除了數據庫。也就是說在此測試文件中的測試沒有全部被執行完前,該測試文件中的測試用例使用的是同一個數據庫。這便是產生沖突異常的原因。 我們點擊單元測試如下按鈕后,將顯示各個測試用例的執行順序: ![](https://img.kancloud.cn/0e/61/0e61c290df02832b0e9ad0516370d3b6_346x364.png) 如上圖所示,在執行save操作前已經執行過了snoUniqueTest方法。而該方法中的測試代碼曾經在數據表中為我們成功的添加了一個學號為032282的學生;在后續執行save方法時,我們再次嘗試在數據表中寫入一個學號為032282的學生,此時便發生了唯一性校驗錯誤。解決這個問題的方法也很簡單----隨機字符串: 我們把before的方法修正如下: ``` this.student.setName("測試名稱"); this.student.setSno("032282"); ? this.student.setSno(RandomString.make(6)); ? ① this.student.setKlass(this.klass); ``` * ① 每次運行都生成一個隨機的學號 然后再測試便可以規避學號互相影響的問題: ![](https://img.kancloud.cn/5b/83/5b83efe5a82f59e9c3df2a2bfbdbbf12_377x388.png) 當然,這也引發了一個snoUniqueTest無法通過的新問題,我們打開該方法再查看一下: ``` @Test public void snoUniqueTest() { this.studentRepository.save(this.student); this.before(); boolean called = false; try { this.studentRepository.save(this.student); } catch (DataIntegrityViolationException e) { called = true; } Assertions.assertThat(called).isTrue(); } ``` 最終發現:由于兩次生成的學生的學號不一樣了,導致第二次學生的保存操作時**未**拋出學號校驗異常,我們將此代碼修正如下: ``` @Test public void snoUniqueTest() { String sno = RandomString.make(6); ① this.student.setSno(sno); ② this.studentRepository.save(this.student); this.before(); this.student.setSno(sno); ② boolean called = false; try { this.studentRepository.save(this.student); } catch (DataIntegrityViolationException e) { called = true; } Assertions.assertThat(called).isTrue(); } ``` * ① 生成一個在方法內部用的學號 * ② 在兩次保存學生前,分別用同一個學號來對學生進行設置 此時我們再測試,所有的單元測試便正常通過了 : ![](https://img.kancloud.cn/8e/86/8e86892d4f3670aa16d993a8870c727b_344x365.png) # 參考文檔 | 名稱 | 鏈接 | 預計學習時長(分) | | --- | --- | --- | | 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.5.8](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.5.8) | - | | PerPersist | [https://docs.oracle.com/javaee/7/api/javax/persistence/PrePersist.html](https://docs.oracle.com/javaee/7/api/javax/persistence/PrePersist.html) | 2 |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看