<GitHub Actions란?/>
- GitHub에서 제공하는 CI/CD 및 자동화 도구
- 프로젝트에 대한 작업 워크플로우를 자동화하고 소프트웨어 개발 과정에서 발생하는 일련의 과정을 클라우드 기반의 실행 환경에서 처리할 수 있도록 함
<CI는 무엇인가?/>
- Continuous Integration의 약자
- 소프트웨어 개발에서 소스 코드 변경 사항을 지속적으로 합치고(통합) 빌드, 테스트하는 개발 방법론
- 코드 통합을 자주 진행함으로써 통합으로 인한 문제를 가능한 한 빨리 발견하고 해결하는 것을 목적으로 함
- CI를 적용할 때의 장점
- 최신 코드 상태를 유지하며 협업 시 문제를 빠르게 공유할 수 있음
- 자동화된 테스트를 통해 코드 품질을 향상시키고 신규 기능의 안정성을 확보함
- 개발, 테스트, 배포 과정에서의 에러를 줄일 수 있음
- CI를 구현하고 관리하는 도구들
- GitHub Actions
- Jenkins
- Travis CI
<프로젝트 소개/>
- 과제 설명 중에 [통합 테스트 또는 단위 테스트 코드를 추가한 경우]에 가산점을 준다고 되어 있다
- 팀프로젝트 할 때 CI를 적용해서 테스트 자동화를 하고 싶었는데 시간이 촉박하고 여유가 없어서 구현하지 못했다
- 이번 기회에서 테스트 자동화를 해보자 싶어서 도전했다
- 먼저 users 앱과 articles 앱에 대한 테스트 코드를 작성해야 한다!
- 전반적으로 성공/실패 테스트를 나눠서 작성했다
- users 앱 테스트코드 간략 설명
- 회원가입 성공: 이메일 형식을 지키고, 비밀번호가 8자 이상인 경우 회원가입에 성공하며 HTTP status는 201 created가 뜬다
- 회원가입 실패: 이메일 형식을 지키지 않았거나 비밀번호가 8자 이하로 입력하면 회원가입에 실패하며 HTTP status는 400 bad request가 뜬다
- 로그인 성공: DB에 저장된 이메일과 비밀번호를 맞게 입력하면 로그인에 성공하며 HTTP status는 200 ok가 뜬다
- 로그인 실패-이메일: DB에 존재하지 않는 이메일 입력하는 경우 존재하지 않는 이메일이라는 메시지를 반환한다. 비밀번호를 맞게 작성해도 이메일이 DB에 존재하지 않으면 HTTP status 400 bad request와 함께 해당 메시지만 반환된다
- 로그인 실패-비밀번호: DB에 존재하는 이메일을 입력하였으나 비밀번호가 틀린 경우 비밀번호를 다시 확인해 달라는 메시지를 반환하며, HTTP staus 400 bad request가 뜬다
- articles 앱 테스트코드 간략 설명
- 게시글에 이미지를 선택사항으로 업로드 할 수 있으므로, 이미지 생성 함수를 구현했다
- 게시글 CURD 테스트는 마찬가지로 성공/실패 경우로 나눠서 구현했다
- setUpTestData 메서드에 user 데이터를 정의한 후, user 객체를 생성했고, article 데이터를 정의했다
- setUp 메서드에선 setUpTestData에서 생성한 user 객체를 활용해서 access_token을 받아 로그인 하는 과정을 담고, article 객체를 생성했다
- 게시글 성공 테스트는 이미지 없는 게시글과 있는 게시글 2개로 나눠서 테스트 코드 작성했다
- 게시글 실패 테스트는 비로그인 한 경우, 제목 미입력, 내용 미입력 3개로 나눠서 테스트 코드 작성했다
- 게시글 목록 조회 테스트는 article 객체를 4개 더 생성해서 총 게시글 5개가 맞게 나오는지 테스트 했다
- 특정 게시글 조회 테스트는 url에 article_id를 넣어서 테스트 했고, 조회에 성공하면 HTTP status 200 ok를 반환한다
- 게시글 수정 테스트는 성공/실패로 나눴고, 작성자가 아닌 사용자가 수정 시도 시 HTTP status 403 forbidden을 띄우며 수정 실패한다
- 게시글 삭제 테스트도 수정 테스트와 마찬가지다
<테스트 자동화하는 방법/>
- 사전 준비 단계
- 레파지토리 생성 후에 Actions 탭을 누르면 Workflow를 생성하는 버튼이 있다
- 아마 내 repo에는 이미 workflow가 있어서 New workflow를 눌러야 새 워크플로우를 생성할 수 있는데 처음 Actions를 눌렀다면 바로 생성할 수 있게끔 되어 있을 거다
- 나는 장고 프로젝트 중이므로 Django를 눌렀다
- 그럼 친절하게도 기본적인 틀이 작성된 코드가 나온다
- 이걸 프로젝트에 맞게 커스텀 해서 오른쪽 위에 Commit changes라는 초록 버튼을 누르면 된다
name: Django CI # 이 워크플로우의 이름을 설정함
on: # 언제 워크플로우를 실행할지 설정함
push: # 브랜치에 push 이벤트가 발생하면 실행됨
branches: [ "main" ] # main 브랜치에서 발생한 push 이벤트에만 실행됨
pull_request: # Pull Request 이벤트가 발생하면 실행됨
branches: [ "main" ] # main 브랜치에 대한 PR 이벤트에만 실행됨
jobs: # 워크플로우 내에서 실행되는 일련의 작업들을 정의함
build: # 작업의 이름을 설정함. 이 경우 작업 이름은 "build"임
runs-on: ubuntu-latest # 작업이 실행되는 가상 환경을 설정함. 이 경우 Ubuntu 최신 버전에서 실행됨
strategy: # 병렬 작업을 실행하는 방법 구성
max-parallel: 4 # 최대 4개의 병렬 작업을 실행함
matrix: # 작업 내에서 사용하는 변수들의 조합을 정의함
python-version: [3.7, 3.8, 3.9] # Python 3.7 3.8 3.9 버전을 사용함
steps: # 작업을 구성하는 순차적 단계를 정의함
- uses: actions/checkout@v3 # GitHub 저장소의 소스 코드를 가상 환경에 가져오는 데 사용되는 actions/checkout 액션을 사용함. @v3은 이 액션의 버전
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with: # 20~23번째 줄: Python 버전 설정을 위해 actions/setup-python 액션을 사용함
python-version: ${{ matrix.python-version }} # 각 python 버전에 해당하는 가상환경 설정
- name: Install Dependencies
run: | # 24~27번째 줄: 프로젝트에 필요한 종속성 설치
python -m pip install --upgrade pip # pip 업그레이드
pip install -r requirements.txt # requirements.txt 파일에 명시된 패키지 설치
- name: Run Tests
run: | # 28~30번째 줄: Django 프로젝트 내에 정의된 테스트 코드 실행
python manage.py test
- 기본으로 제공된 코드에 설명을 붙여보았다
- yaml 파일 커스터마이징
name: Preonboarding CI # 이름 변경
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.11] # 내 컴퓨터에 설치된 Python 버전으로 설정함
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Set Environment Variables
run: | # Django 프로젝트 내 환경변수, GitHub 저장소 내 Secrets에 저장
echo "DEBUG=${{ secrets.DEBUG }}" >> $GITHUB_ENV
echo "SECRET_KEY=${{ secrets.SECRET_KEY }}" >> $GITHUB_ENV
echo "SIGNING_KEY=${{ secrets.SIGNING_KEY }}" >> $GITHUB_ENV
echo "RUNNING_TESTS=True" >> $GITHUB_ENV
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run User App Tests
run: | # 앱별 테스트 실행 코드 분리
python manage.py test users
- name: Run Articles App Tests
run: | # 앱별 테스트 실행 코드 분리
python manage.py test articles
- Django 프로젝트 settings.py 파일에 있는 환경변수에 대한 처리를 추가했다
- SECRET_KEY는 Django 프로젝트 전반에 대한 암호화와 인증에 필요한 코드이고, SIGNING_KEY는 JWT 토큰의 서명 및 검증에 사용됨
- RUNNING_TESTS는 DB 관련한 환경변수인데, DB를 mysql을 사용하고 있는데 mysql 관련 정보를 GitHub secrets에 다 저장을 했는데도 워크플로우가 자꾸 실패로 떠서, RUNNING_TESTS 변수가 True이면 DB를 sqlite를 활용하고, 아니면 mysql을 쓰도록 settings.py를 수정했다
# settings.py
# Check if running in the test environment
RUNNING_TESTS = os.environ.get("RUNNING_TESTS") == "True"
if RUNNING_TESTS:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
else:
MYSQL_DB = env("DB_NAME")
if MYSQL_DB:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": MYSQL_DB,
"USER": env("DB_USER"),
"PASSWORD": env("DB_PASSWORD"),
"HOST": env("DB_HOST"),
"PORT": env("DB_PORT"),
}
}
else:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
- mysql DB 외부 접속 허용하는 걸로 바꿨는데도 안 돼서 그냥 이렇게 할 수밖에 없었다..
- 찾아보니 mysql 설정 파일에서 뭘 바꿔야 한다고 나왔는데 cmd에서 그 설정 파일 편집기가 안 열렸다...
- 여튼 이렇게 설정을 마치니 push를 할 때마다 워크플로우가 실행되고, 테스트 코드가 잘 통과되는 것을 확인할 수 있었다