<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于 TDD 模式編寫 Vue 評論組件(下):Axios 請求后端接口測試

          共 12811字,需瀏覽 26分鐘

           ·

          2021-03-23 23:23

          在本篇教程中,學(xué)院君將以評論創(chuàng)建接口為例,演示如何在 Vue 組件中為通過 Axios 調(diào)用后端接口編寫測試用例。

          一、準(zhǔn)備工作

          后端接口數(shù)據(jù)格式統(tǒng)一

          開始之前,我們先將后端評論創(chuàng)建接口返回?cái)?shù)據(jù)格式進(jìn)行統(tǒng)一,目前表單驗(yàn)證失敗、評論創(chuàng)建成功、數(shù)據(jù)庫異常返回的接口數(shù)據(jù)格式都是不一樣的,這會給前端接口調(diào)用和前后端接口聯(lián)調(diào)造成諸多不便。

          這里學(xué)院君在 app/Http/Controllers 目錄下新建了一個(gè) DataTransformer Trait 來簡單處理控制器動(dòng)作返回的接口數(shù)據(jù)格式:

          <?php
          namespace App\Http\Controllers;

          trait DataTransformer
          {
              public function generateResponseData($success, $message, $data = null)
              
          {
                  return [
                      'success' => $success,   // 是否成功
                      'message' => $message,   // 提示消息
                      'data' => $data          // 如果成功則返回成功數(shù)據(jù),否則顯示錯(cuò)誤明細(xì)(驗(yàn)證表單時(shí)使用)
                  ];
              }
          }

          如代碼所示,現(xiàn)在將所有后端接口返回的數(shù)據(jù)統(tǒng)一為三個(gè)字段,分別標(biāo)識是否成功、消息文案和數(shù)據(jù)明細(xì)。然后我們將 CommentControllerstore 方法改造如下:

          <?php

          namespace App\Http\Controllers;

          use App\Models\Comment;
          use Illuminate\Http\Request;
          use Illuminate\Support\Facades\Log;
          use Illuminate\Support\Facades\Validator;

          class CommentController extends Controller
          {
              use DataTransformer;

              ...

              public function store(Request $request)
              
          {
                  $validator = Validator::make($request->all(), [
                      'content' => 'required'
                  ]);
                  if ($validator->fails()) {
                      return response()->json($this->generateResponseData(false'表單驗(yàn)證失敗', $validator->errors()))
                          ->setStatusCode(422);
                  }
                  $data = $validator->getData();
                  try {
                      $comment = new Comment($data);
                      if ($comment->save()) {
                          return $this->generateResponseData(true'評論保存成功', $comment);
                      }
                      Log::warning('未能保存評論數(shù)據(jù)到數(shù)據(jù)庫: ' . json_encode($data));
                      return response()->json($this->generateResponseData(false'評論保存失敗'))
                          ->setStatusCode(400);
                  } catch (\Throwable $ex) {
                      Log::error('保存評論數(shù)據(jù)到數(shù)據(jù)庫出現(xiàn)異常:' . $ex->getMessage());
                      return response()->json($this->generateResponseData(false'保存數(shù)據(jù)異常'))
                          ->setStatusCode(500);
                  }
              }

          現(xiàn)在創(chuàng)建評論接口不管是字段規(guī)則驗(yàn)證、數(shù)據(jù)保存成功還是數(shù)據(jù)庫處理異常,都會返回統(tǒng)一的 JSON 格式數(shù)據(jù),并且不同的響應(yīng)對應(yīng)不同的狀態(tài)碼,從而方便通過響應(yīng)狀態(tài)碼快速識別響應(yīng)結(jié)果:

          {
              "success": boolean,
              "message": string,
              "data": object|null
          }

          通過 cURL 命令進(jìn)行驗(yàn)證

          為了方便在命令行測試后端接口響應(yīng),可以在 app/Http/Middleware/VerifyCsrfToken.php 中間件中取消該路由的 CSRF 防護(hù):

          class VerifyCsrfToken extends Middleware
          {
              /**
               * The URIs that should be excluded from CSRF verification.
               *
               * @var array
               */

              protected $except = [
                  "comments"
              ];
          }

          當(dāng)然,如果該路由注冊在 routes/api.php 中,則不需要這么做,因?yàn)樗?API 路由都沒有應(yīng)用這個(gè)中間件。

          接下來,就可以通過 curl 命令在終端測試修改后的評論創(chuàng)建接口返回的數(shù)據(jù)格式了,我們先看表單驗(yàn)證失敗的響應(yīng):

          curl -i -H "Accept: application/json" -H "Content-type: application/json" -X POST  -d '{"content":""}'  http://127.0.0.1:8000/comments

          狀態(tài)碼依然是 422,響應(yīng)實(shí)體中包含了 JSON 格式的錯(cuò)誤信息。

          再來看評論創(chuàng)建成功的響應(yīng)信息:

          curl -i -H "Accept: application/json" -H "Content-type: application/json" -X POST  -d '{"content":"測試評論"}'  http://127.0.0.1:8000/comments

          響應(yīng)狀態(tài)碼是 200,響應(yīng)實(shí)體中包含了 JSON 格式的響應(yīng)數(shù)據(jù),評論信息位于 data 屬性中。

          最后再來看看數(shù)據(jù)庫異常情況下的響應(yīng)數(shù)據(jù)(修改數(shù)據(jù)庫連接信息或者在存儲時(shí)將 content 屬性置空即可模擬數(shù)據(jù)庫處理異常):

          響應(yīng)狀態(tài)碼是 500,響應(yīng)實(shí)體中可以通過 message 字段獲取錯(cuò)誤信息。

          二、前端測試用例編寫

          調(diào)整評論組件代碼

          對后端接口有了總體的認(rèn)識之后,接下來我們在 CommentComponent 組件中調(diào)整 addNewComment 方法,將評論列表數(shù)據(jù)添加邏輯改為請求后端評論創(chuàng)建接口獲?。?/p>

          addNewComment() {
              axios.post('comments', {
                  contentthis.content
              }).then(resp => {
                  let comment = resp.data.data;
                  this.comments.push(comment);
                  this.content = '';
              }).catch(error => {
                  console.log(error);
              });
          },

          如果你在終端運(yùn)行著 npm run watch-test,此時(shí)會收到報(bào)錯(cuò)信息:

          這是因?yàn)橹笆峭教砑釉u論數(shù)據(jù)到評論列表屬性的,現(xiàn)在改為通過 Axios 請求后端評論創(chuàng)建接口設(shè)置,變成了異步模式,而且這個(gè)異步模式不同于之前 Vue 組件 DOM 的異步刷新機(jī)制,是一個(gè)完全不可控的行為(比如網(wǎng)絡(luò)異常),因此也不能簡單通過 Vue.nextTick 回調(diào)進(jìn)行測試。

          要測試這種通過對外部接口的調(diào)用進(jìn)而實(shí)現(xiàn) Vue 組件本身的更新,和后端測試外部 HTTP 接口一樣,需要通過攔截 Axios 請求返回偽造的響應(yīng)數(shù)據(jù)來實(shí)現(xiàn),只要返回的數(shù)據(jù)格式滿足上面后端接口約定的 JSON 數(shù)據(jù)格式即可。

          安裝請求測試偽造庫

          JavaScript 生態(tài)中有很多類似的請求測試偽造庫,比如 Axios 官方提供的針對 Axios 請求進(jìn)行模擬和測試的 moxios,以及獨(dú)立的第三方請求測試偽造庫 sinon 等,這里我們主要測試的 Axios 請求,所以使用 moxios 即可。

          使用之前,需要先通過 NPM 安裝它:

          npm install moxios --save-dev

          編寫 Axios 請求測試用例

          接下來,就可以基于 Mocha + moxios 編寫 Axios 請求測試用例了,先打開  setup.js,定義全局變量 axios,以便可以在所有測試用例中使用:

          ...
          global.axios = require('axios');

          然后打開評論測試文件 comment.spec.js,按照 moxios 官方示例 編寫針對 comments 接口的請求測試用例:

          ...
          import moxios from "moxios"

          describe('CommentComponent.vue', () => {
              let wrapper;

              beforeEach(() => {
                  moxios.install(axios)

                  wrapper = mount(CommentComponent, {
                      comment: {
                          content'',
                          votedfalse
                      },
                      comments: []
                  })
              })

              afterEach(() => {
                  moxios.uninstall(axios)
              })

              ...

              it('click submit button will render comment in comments list'function (done{
                  // Given
                  expect(wrapper.find('ul.comments').isVisible()).toBe(false);
                  let comment = '大家好,我是學(xué)院君。';
                  wrapper.find('textarea[name=content]').element.value = comment;
                  wrapper.find('textarea[name=content]').trigger('input');

                  // When
                  wrapper.find('button[type=submit]').trigger('submit');

                  // Then
                  moxios.wait(() => {
                      // 攔截最近一次請求
                      let request = moxios.requests.mostRecent();
                      // 針對該請求返回偽造的響應(yīng)數(shù)據(jù)(請求不會到達(dá)服務(wù)器直接返回)
                      request.respondWith({
                          status200,
                          response: {
                              successtrue,
                              message'評論保存成功',
                              data: {
                                  id1,
                                  content: comment,
                                  votedfalse
                              }
                          }
                      }).then(() => {
                          expect(wrapper.vm.comments.length).toEqual(1);
                          expect(wrapper.vm.comments[0].content).toContain(comment);
                          wrapper.vm.$nextTick(() => {
                              // 需要將這兩個(gè)斷言放到 Vue.nextTick 中執(zhí)行,因?yàn)樗鼈冃枰?nbsp;DOM 刷新之后才會生效
                              expect(wrapper.find('ul.comments').isVisible()).toBe(true);
                              expect(wrapper.find('ul.comments').html()).toContain(comment);
                          });
                          done();
                      })
                  });
              });

              ...
          });

          主要調(diào)整在 Then 部分,通過在 moxios.wait 回調(diào)函數(shù)中攔截最近一次請求,然后針對該請求返回偽造的響應(yīng)數(shù)據(jù),最后在 then 回調(diào)中編寫斷言代碼即可。注意到我們在該測試用例回調(diào)中傳入了一個(gè) done,并且在斷言的最后執(zhí)行了 done() 方法,用于標(biāo)識請求處理完成,退出 moxios.wait,這個(gè)邏輯不能省略。

          另外,在整個(gè)用例的 beforeEachafterEach 方法中,分別進(jìn)行了 moxios 庫的安裝和卸載工作,在這兩個(gè)操作中必須帶上 axios 實(shí)例,否則測試不會通過。

          如果你運(yùn)行了 npm run watch-test,此時(shí)可以看到測試通過,說明我們的 addNewComment 方法調(diào)用沒有問題,接下來,可以與后端接口直接進(jìn)行聯(lián)調(diào)了:

          當(dāng)然,學(xué)院君這里只是拋磚引玉,moxios 還有更多功能,比如定義樁請求和響應(yīng),并且支持正則路由匹配(這在測試更新某個(gè)項(xiàng)目或者獲取項(xiàng)目詳情請求時(shí)很有用),你可以查看官方示例代碼進(jìn)行試驗(yàn),非常簡單,這里就不一一演示了。

          至此,我們的 Vue 組件測試驅(qū)動(dòng)開發(fā)入門之旅就告一段落了,接下來,我們將正式進(jìn)入單頁面應(yīng)用實(shí)戰(zhàn)之旅。

          本系列教程首發(fā)在Laravel學(xué)院(laravelacademy.org),你可以點(diǎn)擊頁面左下角閱讀原文鏈接查看最新更新的教程。

          瀏覽 80
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久九九re | 天天搞天天插 | 狠狠干狠狠干 | 视频一区免费 | 一区二区视频在线播放 |