1. 소개

이 Codelab에서는 Gemini Code Assist가 설계, 빌드 및 테스트, 배포와 같은 소프트웨어 개발 수명 주기 (SDLC)의 주요 단계에서 어떻게 지원하는지 알아봅니다. 전체 애플리케이션을 설계 및 개발하고 Google Cloud에 배포합니다.
기술 이벤트에서 세션을 검색하는 API와 애플리케이션을 빌드할 예정입니다. 각 세션에는 제목, 요약, 기간, 카테고리, 발표자가 한 명 이상 있습니다.
실습할 내용
- OpenAPI 사양을 기반으로 웹 애플리케이션을 처음부터 설계, 빌드, 테스트, 배포
학습할 내용
- Gemini Code Assist를 사용하여 OpenAPI 사양을 생성하는 방법
- Gemini Code Assist 코드 생성 기능을 사용하여 OpenAPI 사양용 Python Flask 애플리케이션을 개발하는 방법
- Gemini Code Assist를 사용하여 Python Flask 애플리케이션의 웹 프런트엔드를 생성하는 방법
- Gemini Code Assist를 사용하여 Google Cloud Run에 애플리케이션을 배포하는 방법에 대한 지원을 받는 방법
- 애플리케이션을 빌드하고 테스트하는 동안 코드 설명, 테스트 사례 생성과 같은 Gemini Code Assist 기능 사용
필요한 항목
- Chrome 웹브라우저
- Gmail 계정
- 결제가 사용 설정된 Cloud 프로젝트
- Cloud 프로젝트에 Gemini Code Assist가 사용 설정됨
이 실습은 초보자를 포함한 모든 수준의 개발자를 대상으로 합니다. 샘플 애플리케이션은 Python 언어로 작성되어 있지만 Python 프로그래밍에 익숙하지 않아도 내용을 이해할 수 있습니다. 여기서는 Gemini Code Assist의 기능을 익히는 데 중점을 둘 예정입니다.
2. Gemini Code Assist 설정
이 섹션에서는 실습을 시작하는 데 필요한 모든 사항을 다룹니다.
Cloud Shell IDE에서 Gemini Code Assist 사용 설정
Codelab의 나머지 부분에서는 완전 관리형 Code OSS 기반 개발 환경인 Cloud Shell IDE를 사용합니다. Cloud Shell IDE에서 Code Assist를 사용 설정하고 구성해야 하며 단계는 아래와 같습니다.
- ide.cloud.google.com을 방문합니다. IDE가 표시되는 데 시간이 걸릴 수 있으므로 잠시 기다리면서 설정 기본 선택사항을 수락하세요. IDE 설정에 관한 안내가 표시되면 기본 설정으로 완료하세요.
- 그림과 같이 하단 상태 표시줄에서 Cloud Code - 로그인 버튼을 클릭합니다. 안내에 따라 플러그인을 승인합니다. 상태 표시줄에 'Cloud Code - 프로젝트 없음'이 표시되면 이를 선택한 다음 작업하려는 프로젝트 목록에서 특정 Google Cloud 프로젝트를 선택합니다.

- 오른쪽 하단에 있는 코드 어시스트 버튼을 클릭하고 올바른 Google Cloud 프로젝트를 다시 한번 선택합니다. Cloud AI Companion API를 사용 설정하라는 메시지가 표시되면 사용 설정하고 계속 진행합니다.
- Google Cloud 프로젝트를 선택한 후 상태 표시줄의 Cloud Code 상태 메시지에서 아래 표시된 것처럼 오른쪽에 코드 어시스턴트가 사용 설정되어 있는지 확인합니다.

이제 Gemini Code Assist를 사용할 수 있습니다.
3. Firestore 설정
Cloud Firestore는 애플리케이션 데이터의 백엔드로 사용할 완전 관리형 서버리스 문서 데이터베이스입니다. Cloud Firestore의 데이터는 문서의 컬렉션으로 구조화됩니다.
기본 Firestore 데이터베이스에 sessions이라는 컬렉션을 만들어야 합니다. 이 컬렉션에는 애플리케이션에서 사용할 샘플 데이터 (문서)가 저장됩니다.
아래와 같이 Cloud Shell IDE 내에서 기본 메뉴를 통해 터미널을 엽니다.

sessions이라는 컬렉션을 만들어야 합니다. 여기에는 샘플 세션 문서 목록이 포함됩니다. 각 문서에는 다음과 같은 속성이 있습니다.
- title: 문자열
- categories: 문자열 배열
- speakers: 문자열 배열
- duration: 문자열
- summary: 문자열
샘플 데이터가 포함된 파일을 자체 프로젝트의 버킷에 복사하여 이 컬렉션에 샘플 데이터를 채워 보겠습니다. 그런 다음 gcloud firestore import 명령어를 통해 컬렉션을 가져올 수 있습니다.
Firestore 데이터베이스 초기화
Cloud 콘솔에서 Firestore 페이지로 이동합니다.
프로젝트에서 이전에 Firestore 데이터베이스를 초기화한 적이 없는 경우 default 데이터베이스를 만듭니다. 데이터베이스를 만드는 동안 다음 값을 사용합니다.
- Firestore 모드:
Native - 위치: 위치 유형을
Region으로 선택하고 애플리케이션에 적합한 리전을 선택합니다. 다음 단계에서 버킷 위치에 필요하므로 이 위치를 기록해 둡니다. - 데이터베이스를 만듭니다.

이제 아래 단계에 따라 sessions 컬렉션을 만듭니다.
- 아래에 제공된
gsutil명령어를 사용하여 프로젝트에 버킷을 만듭니다. 아래 명령어에서<PROJECT_ID>변수를 Google Cloud 프로젝트 ID로 바꿉니다.<BUCKET_LOCATION>을 기본 Firestore 데이터베이스의 지리적 영역에 해당하는 리전 이름으로 바꿉니다 (이전 단계에서 확인). 이는 US-WEST1, EUROPE-WEST1, ASIA-EAST1일 수 있습니다.
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
- 이제 버킷이 생성되었으므로 Firebase 데이터베이스로 가져오기 전에 준비한 데이터베이스 내보내기를 이 버킷에 복사해야 합니다. 아래 명령어를 사용하세요.
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256 gs://<PROJECT_ID>-my-bucket
가져올 데이터가 있으므로 이제 생성한 Firebase 데이터베이스 (default)로 데이터를 가져오는 마지막 단계로 이동할 수 있습니다.
- 아래에 제공된 gcloud 명령어를 사용합니다.
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256
가져오기는 몇 초가 걸리며 완료되면 https://console.cloud.google.com/firestore/databases로 이동하여 Firestore 데이터베이스와 컬렉션을 검증할 수 있습니다. 아래와 같이 default 데이터베이스와 sessions 컬렉션을 선택합니다.

이렇게 하면 애플리케이션에서 사용할 Firestore 컬렉션이 생성됩니다.
4. 애플리케이션 템플릿 만들기
Codelab의 나머지 부분에서 사용할 샘플 애플리케이션 (Python Flask 애플리케이션)을 만들어 보겠습니다. 이 애플리케이션은 기술 컨퍼런스에서 제공되는 세션을 검색합니다.
다음 단계를 따르세요.
- 아래의 상태 표시줄에서 Google Cloud 프로젝트 이름을 클릭합니다.

- 옵션 목록이 표시됩니다. 아래 목록에서 새 애플리케이션을 클릭합니다.

- Cloud Run 애플리케이션을 선택합니다 (앱의 런타임이 됨).
- Python(Flask): Cloud Run 애플리케이션 템플릿을 선택합니다.
- 애플리케이션에 이름을 지정하고 원하는 위치에 저장합니다.
- 애플리케이션이 생성되었음을 알리는 알림이 표시되며 아래와 같이 애플리케이션이 로드된 새 창이 열립니다.
README.md파일이 열립니다. 이제 이 뷰를 닫아도 됩니다.

5. Gemini Code Assist와의 상호작용
이 실습에서는 VS Code에서 Cloud Code 확장 프로그램의 일부이며, Cloud Shell IDE 내에서 사용할 수 있는 Gemini Code Assist 채팅을 사용합니다. 왼쪽 탐색 메뉴에서 코드 어시스트 버튼을 클릭하면 불러올 수 있습니다. 왼쪽 탐색 툴바에서 Code Assist 아이콘
을 찾아 클릭합니다.
그러면 Cloud Shell IDE 내에 코드 지원 채팅 창이 표시되며 코드 지원과 채팅할 수 있습니다.

상단의 휴지통 아이콘을 확인하세요. Code Assist 채팅 기록의 컨텍스트를 재설정하는 방법입니다. 또한 이 채팅 상호작용은 IDE에서 작업 중인 파일과 관련이 있습니다.
6. API 설계
첫 번째 단계는 설계 단계에서 Gemini Code Assist의 지원을 받는 것입니다. 이 단계에서는 검색할 항목 (이벤트의 기술 세션)의 OpenAPI 사양을 생성합니다.
다음 프롬프트를 입력합니다.
Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.
이렇게 하면 다양한 쿼리 매개변수를 통해 세션을 검색하기 위한 OpenAPI 사양이 생성됩니다. 사양 샘플은 다음과 같습니다.
openapi: 3.0.0
info:
title: Sessions API
description: This API allows you to retrieve all sessions, sessions by category, and session by id.
version: 1.0.0
servers:
- url: https://sessions.example.com
paths:
/sessions:
get:
summary: Get all sessions
operationId: getSessions
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Session'
/sessions/{id}:
get:
summary: Get session by id
operationId: getSessionById
parameters:
- name: id
in: path
required: true
description: The id of the session
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Session'
/sessions/categories/{category}:
get:
summary: Get sessions by category
operationId: getSessionsByCategory
parameters:
- name: category
in: path
required: true
description: The category of the sessions
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Session'
components:
schemas:
Session:
type: object
properties:
id:
type: string
description: The id of the session
title:
type: string
description: The title of the session
speakers:
type: array
items:
type: string
description: The list of speakers for the session
categories:
type: array
items:
type: string
description: The list of categories for the session
summary:
type: string
description: The summary of the session
duration:
type: string
description: The duration of the session
사양에는 다음이 포함되어 있습니다.
- 세션 유형에 정의된 스키마입니다.
- 정의된 API 경로가 여러 개입니다.
/sessions/sessions/{id}/sessions/categories/{category}
최상위 폴더에 sessionsapi.yaml이라는 파일을 만들고 '현재 파일에 삽입' 옵션(+ 버튼)을 사용하여 Code Assist 채팅 창에서 콘텐츠를 복사하고 Cloud Shell IDE에서 파일을 열어 둡니다.
이때 Gemini Code Assist의 흥미로운 기능인 인용을 확인할 수 있습니다. 이 정보는 생성된 코드가 기존 오픈소스 코드와 같은 다른 소스에서 직접 길게 인용될 때 개발자에게 표시됩니다. 개발자가 소스와 라이선스를 통해 소스를 어떻게 사용할지 결정할 수 있습니다.
생성된 콘텐츠가 괜찮다고 가정하면 이제 이 사양 문서를 사용하여 Python Flask 애플리케이션을 생성할 수 있습니다.
7. 애플리케이션 생성
이제 Code Assist에 애플리케이션을 생성해 달라고 요청합니다. sessionsapi.yaml 파일을 열고 다음 프롬프트를 입력합니다.
Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.
그러면 OpenAPI 사양 파일에 지정된 기능과 경로를 기반으로 하는 Python Flask 애플리케이션의 스켈레톤이 제공됩니다.
제공되는 Python Flask 애플리케이션 코드는 다음과 유사해야 합니다.
from flask import Flask, jsonify, request
app = Flask(__name__)
sessions = [
{
"id": "1",
"title": "Session 1",
"speakers": ["Speaker 1", "Speaker 2"],
"categories": ["Category 1", "Category 2"],
"summary": "This is a summary of session 1.",
"duration": "1 hour",
},
{
"id": "2",
"title": "Session 2",
"speakers": ["Speaker 3", "Speaker 4"],
"categories": ["Category 3", "Category 4"],
"summary": "This is a summary of session 2.",
"duration": "1 hour 30 minutes",
},
]
@app.route('/sessions', methods=['GET'])
def get_sessions():
return jsonify(sessions)
@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
session = next((session for session in sessions if session['id'] == id), None)
if session is None:
return jsonify({}), 404
return jsonify(session)
@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
sessions_by_category = [session for session in sessions if category in session['categories']]
return jsonify(sessions_by_category)
if __name__ == '__main__':
app.run()
이전 단계의 일부로 생성된 기존 app.py 파일이 있습니다. Code Assist에서 생성된 코드로 내용을 바꾸고 파일을 저장하면 됩니다.
app.run() 줄을 변경하여 포트 8080과 호스트 주소 0.0.0.0을 사용하고 로컬 실행 중에 디버그 모드로 실행하려고 합니다.방법은 다음과 같습니다. 먼저 다음 줄을 강조 표시하거나 선택합니다.
app.run()
그런 다음 Code Assist 채팅 인터페이스에 Explain this. 프롬프트를 입력합니다.
그러면 해당 행에 대한 자세한 설명이 표시됩니다. 아래에 예가 나와 있습니다.

이제 다음 프롬프트를 사용하세요.
update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode
생성된 추천 코드는 다음과 같습니다.
app.run(host='0.0.0.0', port=8080, debug=True)
이 스니펫으로 app.py 파일을 업데이트해야 합니다.
애플리케이션을 로컬로 실행
이제 애플리케이션을 로컬로 실행하여 시작할 때 설정한 애플리케이션 요구사항을 검증해 보겠습니다.
첫 번째 단계는 requirements.txt의 Python 패키지 종속 항목이 가상 환경에 설치되도록 가상 Python 환경을 만드는 것입니다. 이렇게 하려면 Cloud Shell IDE의 명령어 팔레트 (Ctrl+Shift+P)로 이동하여 Python 환경 만들기를 입력합니다. 다음 단계를 따라 가상 환경 (venv), Python 3.x 인터프리터, requirements.txt 파일을 선택합니다.
환경이 생성되면 새 터미널 창 (Ctrl+Shift+`)을 실행하고 다음 명령어를 입력합니다.
python app.py
실행 샘플은 아래와 같습니다.
(.venv) romin@cloudshell: $ python app.py
* Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8080
* Running on http://10.88.0.3:8080
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 132-247-368
이제 다음 URL에서 API를 미리 볼 수 있습니다. 개발 서버가 포트 8080에서 실행 중이라고 가정합니다. 그렇지 않은 경우 적절한 포트 번호로 변경하세요.
https://<host-name>:8080/sessionshttps://<host-name>:8080/sessions/{id}https://<host-name>:8080/sessions/categories/{category}
아래 단계를 따라 이러한 URL을 사용하여 app.py 파일에 포함된 JSON 데이터를 검색할 수 있는지 확인하세요.
새 터미널 창을 열고 다음 명령어를 실행해 보세요.
curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME>
8. 코드 리팩터링
app.py에 하드 코딩된 샘플 JSON 데이터를 포함하는 대신 코드와 데이터 간의 명확한 분리를 유지할 수 있도록 다른 모듈로 분리/추출하는 것이 좋습니다. 그럼 시작해 보겠습니다.
app.py 파일을 열어 두고 다음 프롬프트를 입력합니다.
Can I improve this code and separate out the sessions data from this app.py file?
이렇게 하면 방법을 제안해 줍니다. 다음은 Google에서 받은 제안의 샘플이며, 이와 비슷한 제안을 받게 됩니다.

Code Assist에서 제안한 대로 데이터를 sessions.py 파일로 분리해 보겠습니다.
sessions.py이라는 새 파일을 만듭니다.
, 콘텐츠가 JSON 목록인 데이터는 아래와 같습니다.
sessions = [
{
"id": "1",
"title": "Session 1",
"speakers": ["Speaker 1", "Speaker 2"],
"categories": ["Category 1", "Category 2"],
"summary": "This is a summary of session 1.",
"duration": "1 hour",
},
{
"id": "2",
"title": "Session 2",
"speakers": ["Speaker 3", "Speaker 4"],
"categories": ["Category 3", "Category 4"],
"summary": "This is a summary of session 2.",
"duration": "1 hour 30 minutes",
},
]
이제 app.py 파일이 훨씬 간소화되었으며 아래와 같이 표시됩니다.
from flask import Flask, jsonify, request
from sessions import sessions
app = Flask(__name__)
@app.route('/sessions', methods=['GET'])
def get_sessions():
return jsonify(sessions.sessions)
@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
session = next((session for session in sessions.sessions if session['id'] == id), None)
if session is None:
return jsonify({}), 404
return jsonify(session)
@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
return jsonify(sessions_by_category)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
리팩터링된 변경사항을 사용하여 애플리케이션을 로컬에서 실행하고 API를 사용할 수 있는지 확인합니다. Python 개발 서버가 아직 실행 중일 수 있으므로 이전 단계의 curl 명령어만 다시 호출하면 됩니다.
9. Firestore 컬렉션과 통합
다음 단계는 세션에 대해 가지고 있는 로컬 인메모리 JSON 목록에서 벗어나 이 Codelab 시작 시 만든 Firestore 데이터베이스의 sessions 컬렉션에 애플리케이션을 연결하는 것입니다.
sessions.py 파일을 열어 두고 다음 프롬프트를 입력합니다.
Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore.
Firestore 컬렉션에서 모든 세션을 읽으라는 다음과 같은 제안이 접수되었습니다.
import google.cloud.firestore
# Create a Firestore client
db = google.cloud.firestore.Client()
# Get the sessions collection
sessions_collection = db.collection("sessions")
# Create a list of sessions
sessions = []
# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
session = doc.to_dict()
session["id"] = doc.id
sessions.append(session)
sessions.py에 코드를 통합하세요.
Flask 개발 서버가 로컬에서 실행 중인 경우 Python 모듈을 찾을 수 없다는 불만을 제기하며 애플리케이션이 종료되었을 수 있습니다.
예를 들어 다음과 같이 Code Assist에 requirements.txt 파일에 추가해야 하는 Python 모듈에 관해 물어볼 수 있습니다.
Which Python package needs to be installed to make the firestore code work?
그러면 Python 모듈의 이름 (예: google-cloud-firestore)이 제공됩니다. 이 이름을 requirements.txt 파일에 추가합니다.
새로 추가된 모듈 (google-cloud-firestore)을 사용하여 Python 환경을 다시 만들어야 합니다. 이렇게 하려면 기존 터미널 창에서 다음 명령어를 실행하세요.
pip install -r requirements.txt
애플리케이션을 다시 실행하고 (python app.py로 다시 시작) /sessions URL을 방문합니다. 이제 sessions 컬렉션에 추가한 샘플 문서를 가져와야 합니다.

이전 단계에서 설명한 대로 다른 URI를 쿼리하여 특정 세션이나 특정 카테고리의 모든 세션을 가져올 수 있습니다.
10. 코드 설명
지금 Gemini Code Assist의 "Explain this" 기능을 사용하여 코드에 대해 잘 이해하는 것이 좋습니다. 파일로 이동하거나 특정 코드 스니펫을 선택하고 다음 프롬프트를 사용하여 Code Assist에 요청하세요. Explain this
연습으로 sessions.py 파일을 방문하여 Firestore 관련 코드를 강조 표시하고 해당 코드에 대한 설명을 확인하세요. Python 코드뿐만 아니라 프로젝트의 다른 파일에서도 이 기능을 사용해 보세요.
11. 웹 애플리케이션 생성
이제 API를 생성하고 라이브 Firestore 컬렉션과 통합했으므로 애플리케이션의 웹 기반 프런트엔드를 생성해 보겠습니다. 현재 웹 프런트엔드는 특정 카테고리에 속하는 세션을 검색할 수 있는 등 기능을 최소한으로 유지합니다. /sessions/categories/{category}와 같은 API 경로가 있으므로 웹 애플리케이션이 이를 호출하고 결과를 검색해야 합니다.
바로 시작하겠습니다. Code Assist에 다음 프롬프트를 입력합니다.
Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.
이렇게 하면 JavaScript와 CSS가 삽입된 웹 애플리케이션 HTML이 생성됩니다. 또한 루트 또는 기본 URL을 방문하는 모든 사용자에게 홈페이지가 제공되도록 app.py 파일에 새 경로를 추가하라는 메시지가 표시됩니다. 해당 정보가 언급되지 않은 경우 질문하거나 아래 스니펫을 사용하세요.
@app.route('/')
def index():
return render_template('index.html')
index.html로 저장할 수 있지만 이 파일을 저장해야 하는 위치 (즉, 폴더)에 관한 질문이 있을 수 있습니다. Code Assist에 후속 질문을 할 수 있습니다.
Given that I am using the flask framework, where should I put the index.html file?
render_template 프레임워크를 사용하므로 index.html 파일을 templates 폴더 안에 배치해야 한다는 명확한 정보를 제공해야 합니다. 이 Codelab을 시작할 때 Flask 템플릿을 기반으로 애플리케이션을 생성했으므로 이 폴더를 사용할 수 있습니다. 따라서 기존 index.html 파일이 있으며 여기에서 생성된 새 파일로 콘텐츠를 대체하면 됩니다. Code Assist는 app.py 파일에서 render_template을 가져오라고도 언급합니다.
index.html 파일에 웹 애플리케이션 코드를 저장하고 templates 폴더에 파일을 배치합니다.
애플리케이션을 로컬로 실행
이제 애플리케이션을 로컬로 실행하여 시작할 때 설정한 애플리케이션 요구사항을 검증해 보겠습니다.
로컬 Flask 서버가 계속 실행 중이고 오류가 표시되지 않는지 확인합니다. 오류가 있는 경우 이를 해결하고 서버를 시작합니다.
실행되면 애플리케이션의 홈 URL을 방문합니다. 아래와 같이 제공된 index.html 파일이 표시됩니다.

데이터의 카테고리 중 하나를 입력으로 제공하고 (예: AI) Search 버튼을 클릭합니다. 그러면 AI 카테고리로 태그된 세션이 표시됩니다.

선택사항으로 각 세션의 기간, 카테고리, 발표자, 요약과 같은 추가 메타데이터를 표시할 수 있습니다.
12. 테스트 사례 생성
세션 API가 생성되었으므로 이제 Gemini Code Assist를 사용하여 다양한 API 경로의 단위 테스트 사례를 생성할 차례입니다.
app.py 파일을 열어 두고 다음 프롬프트를 입력합니다.
Generate unit test cases for app routes. Use unittest module.
다음과 같은 응답을 받았습니다.
import unittest
from app import app
class FlaskAppTestCase(unittest.TestCase):
def test_index(self):
tester = app.test_client()
response = tester.get('/')
self.assertEqual(response.status_code, 200)
def test_get_sessions(self):
tester = app.test_client()
response = tester.get('/sessions')
self.assertEqual(response.status_code, 200)
def test_get_session_by_id(self):
tester = app.test_client()
response = tester.get('/sessions/1')
self.assertEqual(response.status_code, 200)
def test_get_sessions_by_category(self):
tester = app.test_client()
response = tester.get('/sessions/categories/category1')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
위 코드를 사용하여 tests.py이라는 파일을 만듭니다.
테스트 사례 생성 관련 참고사항
위와 다른 코드 목록이 표시될 수 있으며, 이로 인해 테스트 사례를 실행하는 데 문제가 발생할 수 있습니다. 예를 들어 일부 실행에서 다음 주요 코드 부분이 누락되었습니다.
from app import app
위 코드는 테스트 사례를 호출할 기존 Flask 앱을 가져오는 데 필요합니다.
if __name__ == '__main__':
`unittest.main()`
위 코드는 테스트 사례를 실행하는 데 필요합니다.
각 테스트 사례를 살펴보고 생성된 코드의 assertEqual 및 기타 조건을 확인하여 작동하는지 확인하는 것이 좋습니다. 데이터가 Firestore 컬렉션에 외부에 있으므로 액세스하지 못할 수 있으며 그 결과 일부 더미 데이터를 사용하여 테스트가 실패할 수 있습니다. 따라서 테스트 사례를 적절하게 수정하거나 당장 필요하지 않은 테스트 사례를 주석 처리하세요.
데모로 다음 명령어를 사용하여 테스트 사례를 실행했습니다 (로컬 API 엔드포인트에 호출이 이루어지므로 로컬 개발 서버를 실행해야 함).
python tests.py
다음과 같은 요약 결과를 얻었습니다.
Ran 4 tests in 0.274s
FAILED (failures=2)
세션 ID가 세 번째 테스트에서 올바르지 않고 category1라는 카테고리가 없으므로 이는 실제로 올바릅니다.
.
따라서 테스트 사례를 적절하게 조정하고 테스트합니다.
13. 테스트 기반 개발
이제 테스트 기반 개발 (TDD) 방법론에 따라 세션 API에 새 검색 메서드를 추가해 보겠습니다. TDD는 먼저 테스트 사례를 작성하고, 구현이 부족하여 테스트가 실패하도록 한 다음, Gemini Code Assist를 사용하여 누락된 구현을 생성하여 테스트를 통과하는 것입니다.
tests.py 파일로 이동합니다 (tests.py 파일에 통과하는 모든 테스트가 있다고 가정). Code Assist에 다음 프롬프트를 입력합니다.
Generate a new test case to search for sessions by speaker
이를 통해 다음 테스트 사례 구현이 제공되었으며, 이 구현은 tests.py 파일에 적절히 삽입되었습니다.
def test_get_sessions_by_speaker(self):
tester = app.test_client()
response = tester.get('/sessions/speakers/speaker1')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])
테스트를 실행하면 다음 오류가 표시됩니다.
$ python tests.py
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200
----------------------------------------------------------------------
Ran 3 tests in 0.010s
FAILED (failures=1)
테스트 사례에서 (/sessions/speakers/) 경로를 호출했지만 app.py에 해당 경로가 구현되어 있지 않기 때문입니다.
Code Assist에 구현을 제공해 달라고 요청해 보겠습니다. app.py 파일로 이동하여 Code Assist에 다음 프롬프트를 제공합니다.
Add a new route to search for sessions by a specific speaker
Code Assist에서 제안한 다음 구현을 app.py 파일에 추가했습니다.
@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
return jsonify(sessions_by_speaker)
tests.py 파일을 다시 확인하고 빠른 확인을 위해 테스트 사례를 다음과 같이 수정했습니다.
def test_get_sessions_by_speaker(self):
tester = app.test_client()
response = tester.get('/sessions/speakers/Romin Irani')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json), 1)
테스트가 정상적으로 실행되었습니다. 생성된 테스트 사례를 살펴보고, Firestore에 있을 수 있는 데이터에 따라 약간 조정하고, Python 단위 테스트 사례에 적절한 assert* 메서드를 포함하는 것은 연습으로 남겨 두겠습니다.
14. Google Cloud Run에 배포
이제 개발 품질이 만족스러우므로 마지막 단계는 이 애플리케이션을 Google Cloud Run에 배포하는 것입니다. 하지만 혹시 잊은 것이 없는지 Code Assist에 물어보는 것이 좋을 것 같습니다. app.py을 열고 다음 프롬프트를 제출합니다.
Is there something here I should change before I deploy to production?
디버깅 플래그를 사용 중지로 설정하는 것을 잊었으니 물어보길 잘했습니다.

표시된 대로 디버깅을 사용 중지하고 Gemini Code Assist에 먼저 컨테이너를 빌드하지 않고 소스에서 직접 Cloud Run에 애플리케이션을 배포하는 데 사용할 수 있는 gcloud 명령어를 도와달라고 요청합니다.
다음 프롬프트를 입력합니다.
I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?
위 프롬프트의 변형을 몇 가지 시도해 보세요. 다음과 같은 방법도 시도했습니다.
I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?
다음 gcloud 명령어를 사용하는 것이 좋습니다.
gcloud run deploy sessions --source .
다음과 같은 항목도 표시될 수 있습니다.
gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated
애플리케이션의 루트 폴더에서 위 명령어를 실행합니다. region을 묻는 메시지가 표시되면 us-central1을 선택하고 unauthenticated invocations 허용을 묻는 메시지가 표시되면 Y을 선택합니다. Artifact Registry, Cloud Build, Cloud Run과 같은 Google Cloud API를 사용 설정하고 Artifact Registry 저장소를 만들 권한을 부여하라는 메시지가 표시될 수도 있습니다. 권한을 부여하세요.
배포 프로세스를 완료하는 데 약 2분이 소요되므로 잠시 기다려 주세요.
배포가 완료되면 Cloud Run 서비스 URL이 표시됩니다. 해당 공개 URL을 방문하면 동일한 웹 애플리케이션이 배포되어 정상적으로 실행되는 것을 확인할 수 있습니다.

축하합니다. 잘하셨습니다.
15. (선택사항) Cloud Logging 사용
애플리케이션 로그가 Google Cloud 서비스 (Cloud Logging) 중 하나에 중앙 집중화되도록 애플리케이션에 로깅을 도입할 수 있습니다. 그런 다음 관측 가능성 Gemini 기능을 사용하여 로그 항목을 파악할 수도 있습니다.
이렇게 하려면 먼저 Google Cloud의 기존 Python Cloud Logging 라이브러리를 사용하여 정보, 경고 또는 오류 메시지를 로깅해야 합니다 (로그 / 심각도 수준에 따라 다름).
먼저 Code Assist에 질문해 보겠습니다. 다음 프롬프트를 사용해 보세요.
How do I use the google-cloud-logging package in Python?
아래와 같이 이에 관한 정보가 제공되는 대답이 표시됩니다.

카테고리별로 세션을 검색하는 함수에 로깅 문을 추가해 보겠습니다.
먼저 requirements.txt 파일에 google-cloud-logging Python 패키지를 추가합니다.
다음은 로깅을 구현하기 위해 코드를 통합한 방법을 보여주는 코드 스니펫입니다.
...
from google.cloud import logging
...
app = Flask(__name__)
# Create a logger
logger = logging.Client().logger('my-log')
@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
logger.log_text(f"Fetching sessions with category {category}")
sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
return jsonify(sessions_by_category)
# # Other App Routes
이전 섹션과 동일한 명령어를 사용하여 서비스를 Cloud Run에 다시 배포하고 배포가 완료되면 /sessions/categories/<category> 엔드포인트에 대한 호출을 몇 번 실행합니다.
Cloud Console → Logs Explorer으로 이동합니다.

아래와 같이 이러한 로깅 문으로 필터링할 수 있습니다.

로그 문을 클릭하고 펼친 다음 Explain this log entry을 클릭하면 Gemini를 사용하여 로그 항목을 설명할 수 있습니다. Google Cloud를 위한 Gemini를 사용 설정하지 않은 경우 Cloud AI Companion API를 사용 설정하라는 메시지가 표시됩니다. 안내에 따라 진행해 주세요.
샘플 응답은 아래와 같습니다.

16. 축하합니다
축하합니다. 처음부터 애플리케이션을 빌드하고 설계, 빌드, 테스트, 배포 등 SDLC의 여러 측면에서 Gemini Code Assist를 사용했습니다.
다음 단계
다음 Codelab을 확인하세요.