iT邦幫忙

3

[不做怎麼知道系列之Android開發者的30天後端養成故事 Day13] - 老闆,來碗自動化測試吧 #讓科技幫你省時間 #持續整合 #CircleCI

Sam 2020-02-19 22:26:451716 瀏覽

https://ithelp.ithome.com.tw/upload/images/20200219/20124548jW3Xt7BcLq.png

哈囉,我們又見面了,今天我們來玩玩看 CircleCI,體驗一下什麼是 持續整合(Continuous Integration, CI),為什麼需要 自動化測試,跟 持續整合 有什麼關係,以及為什麼需要 持續整合

為什麼需要自動化測試 ?

Day11 玩過了測試,會不會覺得每次完成一段程式碼,還需要自己執行測試檔,重複做同一件事,是一件有點麻煩的事 ?!,所以俗話說得好「科技始於懶惰」,這時候我們就想「阿~ 如果有人可以閒閒沒事等我寫完程式,再幫我跑測試,然後再跟我說結果,就好了~~~」,所以有種方法是,拜託老闆去請一個測試人員,然後我再把 code 丟給他去測試,但是,現在科技進步,你可以讓工具幫你做這件事 !

所以 自動化測試 就出現了,自動化的方法有很多種,我們今天談的是 持續整合 概念中的自動化測試,簡單來說,這個自動化的流程是這樣的,當你把完成的功能程式碼 和 測試程式碼,推到 Github 上(你也可以選擇 pull request 才執行測試),持續整合的工具會檢測到你的程式碼更新,就根據你新的程式碼來跑測試,最後再把結果透過你設定的通知方式,來告訴你這次的測試結果,聽起來是不是挺方便的阿。

所以持續整合(CI)是什麼 ?

持續整合是一種概念,其中 整合 的意思是 新程式碼 與 舊程式碼 的整合,而 持續 的意思是希望能夠在專案的開發過程中,不斷地進行新、舊程式碼整合,每個團隊能夠決定這個 持續 的頻率,可以是每個 commit,可以是每個 pull request,可以是只有 master branch 的每個 commit,依照不同的 CI 平台,可以設定的程度也不一樣。

簡單來說,持續整合,就是幫你做好 開發 與 測試 之間的銜接,當你寫好一段 code,把它 push 到 github 上,由持續整合的工具來幫你做測試,工具再透過 slackemail 告訴你測試結果,讓開發與測試的一切流程比使用飛柔的頭髮還要順。所謂的持續,表示的是,不是等到你把大功能都做好了,才一次做測試,而是每當完成一個段落,就由工具來持續地檢查你新完成的程式碼,跟原有的程式碼是否相容,有沒有影響到你的原有功能。

你所需要做的就是,把 code push 到 github,喝一口水,然後你就知道這段 code 到底有沒有問題了,沒有問題就繼續開發或重構,有問題就回去找 bug。

如果用一句話來表示,就是 持續地 確保 你的程式碼每次更新,都是功能正常的,以上只是針對個人開發的角度來看,當這件事情在多人協作時,更加不容易達到,隨著團隊人數增加,確保程式碼品質的難度,成指數型上升,更何況還有離職與新進人員的經手。

為什麼需要持續整合?

簡言之,讓我們專注在開發,確保品質這種事情就交給工具來做吧。

為什麼是 CircleCI?

關於為什麼要選擇 CircleCI 而不是其他的 CI/CD 平台,可以參考 CircleCI 使用經驗談 | Hwchiu Learning Note

那麼該怎麼持續整合呢 ?

首先,需要先有測試,再告訴 CI 你的執行環境,最後就是在 CI 執行我們的專案,並且執行測試。其中測試包含各種層級的測試方法,從單元測試到整合測試,依照專案規模來決定要執行到什麼層級的測試,還有看你的時間夠不夠寫這麼多測試 XD。

初探 CircleCI

在這邊我們先展示把全新的 django 專案整合到 CircleCI。

我的流程是這樣的

  • 創一個新的 Django Project & Django App
  • 把 Django project 上傳到 Github
  • 註冊 CircleCI & 綁定 Github
  • circleci-project-setup 的分支 merge 回去 master
  • 所以先 git checkout circleci-project-setup branch
  • 修改 config.yml (改成我們想要的 CI 流程)
  • Push 上去 GithubCircleCI 就會執行測試
    (因為現在 test.py 還沒有東西,所以測試會過很正常)
  • 新增一個 view 的 test case (測試 home page 的 status code)
  • 再一次 push 上去 (測試成功,耶)

看起來有點複雜,可是其實很簡單 der,只要抓住兩個重點

  1. config.yml 怎麼寫,每一行代表什麼意思
  2. CircleCI 對你的 Github 做了些什麼?

那麼,我們就開始囉 ~

創一個新的 Django Project & Django App

這部分詳情可以參考 Day4,在這邊只列出大致流程,作為備忘或參考

  • 進到 python virtual environment

    $ django-env\Scripts\activate

  • 利用已安裝的 django,創建新的 project

    $ django-admin startproject demo_web_project

  • 進到 project 目錄裡,並創建新的 app 在 project 裡

    $ cd demo_web_project && django-admin startapp

把 Django project 上傳到 Github

  • 先到 Github 創個 Repository,再到 cmd

    $ git add .

    $ git commit -m "Init"

    $ git remote add origin https://github.com/yourgithub/yourreponame.git

註冊 CircleCI & 綁定 Github

當你在 CircleCI 內連結到 Github 帳號後,就會列出你所有的 repository,我的 Github Repository 叫做 CircleCI_Demo_Web

https://ithelp.ithome.com.tw/upload/images/20200219/20124548opKDLO2Cgc.png

按下 Set Up Project 後,會在你的 Github repo 產生一個新的分支,並且加入一個 .circleci 的資料夾,裡面有個 config.yml 檔,這個 config 檔先不要理它,按下 Add Config 按鈕之後

https://ithelp.ithome.com.tw/upload/images/20200219/20124548zyHVjbuFMN.png

就會自動幫你進行第一次的 pipeline,然後就 FAILED 了,覺得 CircleCI 的預設 config 檔實在是有點爛,一點都沒有 Hello World 的感覺

https://ithelp.ithome.com.tw/upload/images/20200219/20124548PxgJj5MLTY.png

把 circleci-project-setup 的分支 merge 回去 master

是不是想這樣做 ? 可惜,因為 Pipeline FAILED,所以你無法 pull request

https://ithelp.ithome.com.tw/upload/images/20200219/20124548krZR8l20TA.png

修改 config.yml (改成我們想要的 CI 流程)

既然無法 merge 回去 master,那我們就把 config 修好再回去 master 吧

  • 那就在本地端先 checkout 到 circleci-project-setup 的 branch 吧

    $ git checkout remote circleci-project-setup

  • 修改 .circleci/config.yml

    # CircleCI 的版本
    version: 2.1
    
    jobs:
      # 把這個工作取名叫做 `build-and-test`
      build-and-test:
        # 告訴 circleci,我需要 docker 的環境
        docker:
          # 告訴 circleci,我要用 Docker Hub 上的
          # `circleci/python` 的映像檔	
          # 而且 tag 是要 3.8.1 的 tag
          - image: circleci/python:3.8.1
        steps:
          # 第一步
          - checkout
          # 第二步
          - run:
              # 先安裝 django
              command: |
                pip install django~=3.0.3
              # 只是幫這個指令取名字而已
              name: Install
          # 第三步
          - run:
              # 執行 django 的測試
              command: |
                python manage.py test
              name: Test
    
    # 告訴 CircleCI,我要執行的工作,
    # 總共要執行 `build-and-test` 這一個工作
    workflows:
      main:
        jobs:
          - build-and-test
    

總體來講,就是要執行 python manage.py test 這一行而已,其他都是前置步驟

Push 上去 Github → CircleCI 就會執行測試

  • Git Commit & Push

    $ git add .

    $ git commit -m "Update config.yml: Run django test"

    $ git push -u origin circleci-project-setup

  • 切換到 CircleCI 的 Pipeline 頁面 (為了確認執行成功)

因為現在 test.py 還沒有寫任何的測試,所以測試會過很正常

https://ithelp.ithome.com.tw/upload/images/20200219/20124548toaXq6MQXA.png

我的 commit 多做了好幾次 XD,原本以為要在 config 裡面寫 $ python manage.py runserver,之後才能跑 $ python manage.py test,結果不需要,所以才會有第三筆灰色 CANCELED,做到這邊,你應該會看到綠色勾勾才對,因為現在 test.py 裡面還沒有寫測試,怎麼測都應該要會過

新增一個 view 的 test case (測試 home page 的 status code)

tests.py

from django.test import TestCase

class TestHomePageView(TestCase):
    def test_reachable_home(self):
        response = self.client.get('/home/')
        self.assertEqual(response.status_code, 200)

views.py

from django.shortcuts import render

def home_view(request):
	return render(request, 'home.html', {})

yourapp/ 下新增 templates 的資料夾 並 新增一個 home.html,這邊不懂的話可以參考 Day5

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    Hi, circleci and django
</body>
</html>

urls.py

from django.contrib import admin
from django.urls import path

from demo_app.views import home_view

urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/', home_view)
]

settings.py

...

INSTALL_APP = [
	...,
	'yourappname'
]

...
  • 在本地端跑跑看

    $ python manage.py runserver

  • 用瀏覽器到 http://127.0.0.1:8000/home/ 看看有沒有很簡單的網頁出現

https://ithelp.ithome.com.tw/upload/images/20200219/20124548SDsrU2ujIm.png

表示 code 沒問題

  • 執行測試

    $ python manage.py test

$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.011s

OK
Destroying test database for alias 'default'...

至於在執行 test 之前,需不需要先 runserver ? 我自己在測試的時候,不需要 先 runserver 就能啟動測試,而且連頁面的 status code 這種測試,都可以在不 runserver 的情況下測試完成。我有在 stackoverflow 發問 這個問題,大家有興趣可以關注一下後續發展,如果大家有什麼想法,麻煩跟我講一下,同時我也很好奇,只有 django 可以這樣做,還是說其他框架也能做到?

再一次 push 上去 (測試成功,耶)

https://ithelp.ithome.com.tw/upload/images/20200219/20124548U9iOJlbl9J.png

單日心得總結

如果看完還是無法成功的話,可以參考 (2019) Continuous integration for Django projects,我是參考到這篇才成功的,嗚嗚。

其實我最先成功是參考上面那篇,把原本的 django 專案放到 CircleCI 上,能成功連動、進行測試,可是,我完全不知道為什麼可以跑得動,只好努力把 config.yml 研究一下,然後再創一個新專案,重新用我的理解去做一個 config 出來,這就是為什麼今天這篇是用全新專案來講解 XD。

在做的時候還有一個問題是,我一直搞不懂 到底要不要把 Dockerfile 包在專案裡面讓 CircleCIconfig.yml 去讀取阿 ?! 實驗證明,在 config.yml 裡的 docker 那一欄是直接從 Docker Hub 下載的,因為我的第一個成功的專案,裡面就包了各種奇奇怪怪的東西,包括 python virtual environment、dockerfile,覺得那個專案已經髒掉了 XD,所以才做全新專案,用個最乾淨的方式試試看。

好的,這篇我自認為非常難閱讀,太雜、太亂,想解釋觀念、又想帶實作、又想解釋指令,大家就多擔待 QQ

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。



尚未有邦友留言

立即登入留言