<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>

                我們在上個小節中首次使用單元測試來進行組件的單獨開發,本節繼續使用單元測試來自動完成C層的交互。 # 新建測試用例 在上一個測試用例的下方,模仿建一個新的測試用例。 klass/index/index.component.spec.ts ```js it('測試V層的交互操作', () => { }); ``` * 使用`it(string ,function)`來聲明一個測試用例。`string` 是對測試用例的描述,`function`來定義該測試用例的功能。 增加了測試用例后,我們在終端中使用`ng test`來執行測試。 ![](https://img.kancloud.cn/7c/3c/7c3c585475cef99d256c65a03085863a_784x176.png) 測試結果頁顯示我們的當前的測試用例沒有`預測(斷言)`信息。 > 斷言:我`斷`定`說`,一定會發生什么,如果結果與我的斷言不相符則報錯。 ## 驗證雙向數據綁定 在班級index組件的V層中,我們使用了這樣的代碼想達到將C層數據傳給(綁定)V層使用的目的: klass/index/index.component.html ``` <form (ngSubmit)="onQuery()"> <label>名稱:<input type="text" name="params.name"/></label> ① <button>查詢</button> </form> ``` 下面我們使用單元測試來驗證數據是否被綁定成功了。同時,為了防止測試用例的執行順序,我們將當前測試用由`it`變更為`fit`,表示:只執行本測試用例。 klass/index/index.component.spec.ts ``` it('測試V層的交互操作', () => { ? fit('測試V層的交互操作', () => { ? component.params.name = 'test'; ? fixture.detectChanges(); ? }); ``` * ? 設置查詢參數`name`的值為`test`。 * ? 當組件發生變化時,重新渲染組件。 #### 測試 ![](https://img.kancloud.cn/81/1b/811b3f0a7e0b533af37bca4e03c90158_352x179.png) V層中的input表單并沒有如我們所期望的一般變為`test`。由此可見,我們的數據綁定并沒有成功。相信當我們初始化V層的時候,你已經發現了這個前臺綁定的錯誤,在前臺進行數據綁定時,我們應該這樣: ``` <label>名稱:<input type="text" name="params.name"/></label> ? <label>名稱:<input type="text" name="name" [(ngModel)]="params.name"/></label> ? ``` 保存文件后得到如下測試提醒: ``` Failed: Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'. ("<form (ngSubmit)="onQuery()"> <label>名稱:<input type="text" name="name" [ERROR ->][(ngModel)]="params.name"/></label> <button>查詢</button> </form> "): ng:///DynamicTestModule/IndexComponent.html@1:43 ``` 看到該錯誤,相信你一定有種似曾相識的感覺,這是因為該錯誤已經不是首次出現了。錯誤產生的原因是:`NgModel`指令屬于`FormModule`,而我們當前測試未引入`FormModule`,進而報錯。其實該錯誤與前面的`no provider for HttpClient 未找到httpClient的提供者`的錯誤性質是一樣的。在C中引入`HttpClient`則需要引用`HttpClient`所在的模塊`HttpModule`,在V層中使用`ngModel`指令,則需要引用`ngModel`指令所在的模塊`FormsModule`。修正的方法如下: klass/index/index.component.spec.ts ``` import {FormsModule} from '@angular/forms'; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [IndexComponent], imports: [HttpClientTestingModule, FormsModule] ① }) .compileComponents(); })); ``` 此時再查看運行的結果: ![](https://img.kancloud.cn/ba/b9/bab9f478df9ca4c5017d8c59340aeb03_369x163.png) ### 驗證V層向C層綁定數據 剛剛我們驗證了C層向V層的數據綁定,接下來繼續驗證V層向C層的數據綁定。 我們將上個用例的`fit`修改為`it`,然后新建一個`fit`測試用例方法。 klass/index/index.component.spec.ts ``` fit('測試V層向C層綁定', () => { fixture.whenStable().then(() => { ? }); }); ``` * ? 由于V層的渲染需要的一定的時間(很短,肉眼感受不到),所以在進行V層的一些操作時,我們使用`whenStable().then(function)`來等待V層渲染完畢。 在Angular測試中,我們使用如下方法設置`input`的值: klass/index/index.component.spec.ts ``` import {By} from '@angular/platform-browser'; ① fit('測試V層向C層綁定', () => { fixture.whenStable().then(() => { const debugElement = fixture.debugElement; ? const nameInputElement = debugElement.query(By.css('input[name="name"]')); ? const nameInput: HTMLInputElement = nameInputElement.nativeElement; ? nameInput.value = 'test1'; ? nameInput.dispatchEvent(new Event('input')); ? console.log(component.params.name); ? }); }); ``` * ? 獲取**所有**供測試的V層元素。 * ? 通過CSS選擇器來查詢出具體的V層的元素。 * ? 將獲取到的元素轉換為`HTMLInputElement`。 * ? 設置預輸入表單的值。 * ? Angular 不知道我們設置了這個 <input> 元素的 value 屬性。 在通過調用 dispatchEvent() 觸發了該輸入框的 input 事件之前,它不能讀到那個值。 * ? 查看是否成功的綁定到C層。 > 只所以要經過???三步操作是由于:Angular 依賴于`[DebugElement](https://www.angular.cn/api/core/DebugElement)`這個抽象層,就可以安全的橫跨*其支持的所有平臺*。 Angular 不再創建 HTML 元素樹,而是創建`[DebugElement](https://www.angular.cn/api/core/DebugElement)`樹,其中包裹著相應運行平臺上的*原生元素*。`nativeElement`屬性會解開`[DebugElement](https://www.angular.cn/api/core/DebugElement)`,并返回平臺相關的元素對象。簡單的原因就是:由于angular要安全的支持所有平臺。 測試結果: ``` Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 0 of 6 SUCCESS (0 secs / 0 secs) ERROR: 'Spec 'IndexComponent 測試V層向C層綁定' has no expectations.' Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 0 of 6 SUCCESS (0 secs / 0 secs) LOG: 'test1' Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 1 of 6 SUCCESS (0 secs / 0.114 secs) Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 1 of 6 (skipped 5) SUCCESS (0.137 secs / 0.114 secs) TOTAL: 1 SUCCESS TOTAL: 1 SUCCESS ``` ![](https://img.kancloud.cn/e9/ad/e9adcb8a1438fbab3b63cfda9aed7d75_952x676.png) ## 斷言 我們剛剛在控制臺中確認了數據被成功的綁定。但這種確認的方法并不可靠,隨著項目推進、需求變更、團隊人員增加等因素,我們需要越來越多的主觀判斷來保證歷史的功能仍在正常運行。試想下,我們當前的項目有了3個測試用例,如果人為的來確認這3個測試用例是正確的,則需要逐個將`it`方法變更為`fit`方法,然后觀察界面或控制臺來確認組件的正確性。在團隊開發中,往往是由于成員A變更了自己的功能而導致成員B的功能出現錯誤。也就是說如果想保證項目的質量,那么成員A在變更了自己的任意代碼后都應該把項目中所有的單元測試跑一遍,用眼睛來確認一便來確保自己的變更沒有對其它的模塊產生影響。這是不現實的。 單元測試的斷言很好的解決了此問題,每個預期的結果我們都寫在單元測試的代碼中,當其它的成員進行增量開發或是修改時,如果不小心影響了我們的功能,那么此時單元測試會自動告知他。這樣就使得在大型的團隊合作開發的項目中,不會因個別代碼的變動而影響其它模塊的功能了。 `斷言` = `斷定說`,還可以理解為`我預測`、`我期望..`等。下面,我們來逐步增加斷言進而完成前面的單元測試。 klass/index/index.component.spec.ts ``` fit('測試V層向C層綁定', () => { expect(component).toBeTruthy(); ① ? fixture.whenStable().then(() => { const debugElement: DebugElement = fixture.debugElement; const nameInputElement = debugElement.query(By.css('input[name="name"]')); const nameInput: HTMLInputElement = nameInputElement.nativeElement; nameInput.value = 'test1'; nameInput.dispatchEvent(new Event('input')); console.log(component.params.name); ? expect(component.params.name).toBe('test1'); ? ``` * ① 防止報沒有任何期望的錯誤 * ? 期望`component.params.name`的值為`test1` 如果我們將`expect(component.params.name).toBe('test1');`變更為`expect(component.params.name).toBe('test2');`,則會得到如下錯誤:·· ``` Expected 'test1' to be 'test2'. ``` 它是在說:我們期望的是`test2`,但是得到的是`test1`,這與我們規定的期望不致。有了這個期望后,當其它的成員或幾天后的自己不小心犯錯后單元測試便會自動告知我們了。 ### 修正其它的斷言 將此測試用例方法由`fit`變更為`it`后,我們為其它的兩個測試用例增加期望。 ``` it('should create', () => { expect(component).toBeTruthy(); const req = httpTestingController.expectOne('http://localhost:8080/Klass?name='); const klasses = [ new Klass(1, '計科1901班', new Teacher(1, 'zhagnsan', '張三')), new Klass(2, '軟件1902班', new Teacher(2, 'lisi', '李四')) ]; req.flush(klasses); fixture.detectChanges(); fixture.whenStable().then(() => { const debugElement: DebugElement = fixture.debugElement; const tableElement = debugElement.query(By.css('table')); ? const nameInput: HTMLTableElement = tableElement.nativeElement; ? expect(nameInput.rows.length).toBe(3); ? expect(nameInput.rows.item(1).cells.item(1).innerText).toBe('計科1901班'); ? expect(nameInput.rows.item(1).cells.item(2).innerText).toBe('張三'); ? }); }); it('測試V層的交互操作', () => { component.params.name = 'test'; fixture.detectChanges(); fixture.whenStable().then(() => { const debugElement: DebugElement = fixture.debugElement; const nameInputElement = debugElement.query(By.css('input[name="name"]')); const nameInput: HTMLInputElement = nameInputElement.nativeElement; expect(nameInput.value).toBe('test'); }); }); ``` * ?? 查找table元素。 * ? 斷言table中有3行信息:表頭1行+數據2行。 * ? 斷言第1行第1列的值為`計科1901班`。 * ? 斷言第1行第2列的值為`張三`。 > 在實際的開發中,我們可能不會對數據綁定這種較常規的點進行測試。此小節對雙向數據綁定進行了測試,目的在拋磚引玉為以后較復雜的組件測試做基礎積累。 # 參考文檔 | 名稱 | 鏈接 | 預計學習時長(分) | | --- | --- | --- | | 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.2.6](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.2.6) | - | | 組件DOM測試 | [https://www.angular.cn/guide/testing#component-dom-testing](https://www.angular.cn/guide/testing#component-dom-testing) | 15 | | CSS選擇器 | [https://www.w3school.com.cn/cssref/css\_selectors.asp](https://www.w3school.com.cn/cssref/css_selectors.asp) | 10 | | DebugElement | [https://www.angular.cn/api/core/DebugElement](https://www.angular.cn/api/core/DebugElement) | 5 | | HTMLTableElement | [https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLTableElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLTableElement) | 5 | |HTMLInputElement | [https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement) | 5 | | 使用`[dispatchEvent()](https://www.angular.cn/)`修改輸入值 | [https://www.angular.cn/guide/testing#change-an-input-value-with-dispatchevent](https://www.angular.cn/guide/testing#change-an-input-value-with-dispatchevent) | 5 |
                  <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>

                              哎呀哎呀视频在线观看