728x90
반응형

Hurl 실전 활용 가이드: 다양한 예제와 응용 시나리오

Hurl은 HTTP 요청을 간단한 텍스트 형식으로 정의하고 실행할 수 있는 강력한 명령줄 도구입니다. 이 블로그에서는 개발자와 QA 엔지니어가 일상적인 작업에서 Hurl을 효과적으로 활용할 수 있는 다양한 실전 예제를 상세히 살펴보겠습니다.

기본 설치 및 시작하기

Hurl을 사용하기 전에 먼저 설치해야 합니다. 주요 운영체제별 설치 방법은 다음과 같습니다:

macOS (Homebrew 사용)

brew install hurl

Linux (Debian/Ubuntu)

curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl_1.8.0_amd64.deb
sudo dpkg -i hurl_1.8.0_amd64.deb

Windows (Chocolatey 사용)

choco install hurl

설치가 완료되면 다음 명령으로 버전을 확인할 수 있습니다:

hurl --version

예제 1: 기본적인 HTTP GET 요청

가장 간단한 형태의 Hurl 파일은 다음과 같습니다:

# basic-get.hurl
GET https://api.github.com/users/torvalds

이 파일을 basic-get.hurl로 저장한 후 다음 명령어로 실행합니다:

hurl basic-get.hurl

실행 결과로 GitHub API에서 반환한 JSON 응답이 표시됩니다.

예제 2: 응답 검증하기

Hurl의 강력한 기능 중 하나는 응답을 검증하는 기능입니다:

# validate-response.hurl
GET https://api.github.com/users/torvalds

# 상태 코드 검증
HTTP 200

# 헤더 검증
[Asserts]
header "Content-Type" contains "application/json"
header "Server" exists

# JSON 응답 검증
jsonpath "$.login" equals "torvalds"
jsonpath "$.id" greaterThan 1000
jsonpath "$.type" equals "User"

이 예제는 응답의 상태 코드, 헤더, JSON 내용을 검증합니다.

예제 3: POST 요청 보내기

데이터를 서버에 전송하는 POST 요청 예제입니다:

# post-request.hurl
POST https://httpbin.org/post
Content-Type: application/json

{
    "name": "John Doe",
    "email": "john.doe@example.com",
    "message": "Hello from Hurl!"
}

HTTP 200
[Asserts]
jsonpath "$.json.name" equals "John Doe"
jsonpath "$.json.email" equals "john.doe@example.com"

예제 4: 값 캡처 및 재사용

이전 응답에서 값을 캡처하여 후속 요청에 사용하는 강력한 기능입니다:

# capture-and-reuse.hurl
# 첫 번째 요청: 모든 사용자 조회
GET https://jsonplaceholder.typicode.com/users

HTTP 200
[Captures]
user_id: jsonpath "$[0].id"

# 두 번째 요청: 캡처한 ID로 특정 사용자의 게시물 조회
GET https://jsonplaceholder.typicode.com/posts?userId={{user_id}}

HTTP 200
[Asserts]
jsonpath "$[0].userId" equals {{user_id}}

이 예제에서는 첫 번째 응답에서 사용자 ID를 캡처하고, 이를 두 번째 요청의 쿼리 파라미터로 사용합니다.

예제 5: 인증 처리

다양한 인증 방식을 처리하는 예제입니다:

기본 인증(Basic Auth)

# basic-auth.hurl
GET https://httpbin.org/basic-auth/user/passwd
[BasicAuth]
user: user
password: passwd

HTTP 200
[Asserts]
jsonpath "$.authenticated" equals true

OAuth 2.0 토큰 인증

# oauth-token.hurl
# 토큰 획득
POST https://auth-server.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=my-client&client_secret=my-secret

HTTP 200
[Captures]
access_token: jsonpath "$.access_token"

# 토큰 사용
GET https://api.example.com/protected-resource
Authorization: Bearer {{access_token}}

HTTP 200

예제 6: 파일 업로드

멀티파트 폼 데이터를 사용하여 파일을 업로드하는 예제입니다:

# file-upload.hurl
POST https://httpbin.org/post
[MultipartFormData]
field1: value1
field2: value2
file1: file,example.txt;text/plain
file2: file,image.jpg;image/jpeg

HTTP 200
[Asserts]
jsonpath "$.files" exists

예제 7: 쿠키 처리

쿠키를 설정하고 후속 요청에서 사용하는 예제입니다:

# cookie-handling.hurl
# 쿠키 설정
GET https://httpbin.org/cookies/set?cookie1=value1&cookie2=value2

HTTP 302

# 쿠키 확인
GET https://httpbin.org/cookies

HTTP 200
[Asserts]
jsonpath "$.cookies.cookie1" equals "value1"
jsonpath "$.cookies.cookie2" equals "value2"

예제 8: 복잡한 시나리오 테스트

여러 요청을 체이닝하여 복잡한 시나리오를 테스트하는 예제입니다:

# e-commerce-flow.hurl
# 1. 로그인
POST https://demo-shop.example.com/api/login
Content-Type: application/json

{
    "username": "testuser",
    "password": "password123"
}

HTTP 200
[Captures]
token: jsonpath "$.token"
user_id: jsonpath "$.user_id"

# 2. 상품 검색
GET https://demo-shop.example.com/api/products?query=laptop

HTTP 200
[Captures]
product_id: jsonpath "$.products[0].id"

# 3. 장바구니에 상품 추가
POST https://demo-shop.example.com/api/cart
Authorization: Bearer {{token}}
Content-Type: application/json

{
    "user_id": "{{user_id}}",
    "product_id": "{{product_id}}",
    "quantity": 1
}

HTTP 201
[Captures]
cart_id: jsonpath "$.cart_id"

# 4. 주문 생성
POST https://demo-shop.example.com/api/orders
Authorization: Bearer {{token}}
Content-Type: application/json

{
    "user_id": "{{user_id}}",
    "cart_id": "{{cart_id}}",
    "shipping_address": {
        "street": "123 Test St",
        "city": "Test City",
        "zipcode": "12345"
    }
}

HTTP 201
[Asserts]
jsonpath "$.order_status" equals "created"
jsonpath "$.payment_status" equals "pending"

예제 9: XML 응답 처리

XML 응답을 처리하고 검증하는 예제입니다:

# xml-handling.hurl
GET https://httpbin.org/xml

HTTP 200
[Asserts]
xpath "//title" equals "Sample Slide Show"
xpath "count(//slide)" equals "2"
xpath "//slide[@type='all']/title" equals "Wake up to WonderWidgets!"

예제 10: 환경별 설정 관리

개발, 테스트, 프로덕션 환경에 따라 다른 설정을 사용하는 예제입니다:

# api-test.hurl
GET {{base_url}}/api/users

HTTP 200
[Asserts]
jsonpath "$.length" greaterThan 0

이 파일을 실행할 때 변수를 주입하는 방법:

# 개발 환경
hurl --variable base_url=http://dev-api.example.com api-test.hurl

# 테스트 환경
hurl --variable base_url=http://test-api.example.com api-test.hurl

# 프로덕션 환경
hurl --variable base_url=http://api.example.com api-test.hurl

또는 환경 변수 파일을 사용할 수도 있습니다:

# dev.env
base_url=http://dev-api.example.com
api_key=dev-api-key
hurl --variables-file dev.env api-test.hurl

예제 11: CI/CD 파이프라인 통합

Jenkins, GitHub Actions 등의 CI/CD 파이프라인에 Hurl을 통합하는 예제입니다:

GitHub Actions 예제

# .github/workflows/api-test.yml
name: API Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Install Hurl
        run: |
          curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl_1.8.0_amd64.deb
          sudo dpkg -i hurl_1.8.0_amd64.deb

      - name: Run API Tests
        run: hurl --test --glob "tests/**/*.hurl"

예제 12: 성능 테스트 응용

Hurl의 --retry--retry-interval 옵션을 사용한 간단한 성능 테스트:

# performance-test.hurl
GET https://api.example.com/high-load-endpoint

HTTP 200
[Asserts]
duration lessThan 1000

실행 명령:

hurl --retry 10 --retry-interval 1000 performance-test.hurl

예제 13: HTML 응답 테스트

웹사이트의 HTML 응답을 테스트하는 예제입니다:

# html-test.hurl
GET https://example.com

HTTP 200
[Asserts]
header "Content-Type" contains "text/html"
xpath "//title" contains "Example Domain"
xpath "count(//a)" greaterThan 0
xpath "//h1" exists

예제 14: GraphQL 요청

GraphQL API에 요청을 보내는 예제입니다:

# graphql-request.hurl
POST https://api.github.com/graphql
Authorization: Bearer {{github_token}}
Content-Type: application/json

{
    "query": "query { viewer { login name bio repositories(first: 5) { nodes { name url } } } }"
}

HTTP 200
[Asserts]
jsonpath "$.data.viewer.login" exists
jsonpath "$.data.viewer.repositories.nodes" count greaterThan 0

예제 15: 데이터 기반 테스트

CSV 파일의 데이터를 사용하여 여러 테스트 케이스를 실행하는 예제입니다:

users.csv 파일:

id,name,email
1,John,john@example.com
2,Jane,jane@example.com
3,Bob,bob@example.com

스크립트:

#!/bin/bash
while IFS=, read -r id name email
do
    if [ "$id" != "id" ]; then  # 헤더 행 건너뛰기
        echo "Testing user $name"
        hurl --variable id="$id" --variable name="$name" --variable email="$email" user-test.hurl
    fi
done < users.csv

user-test.hurl 파일:

# 사용자 생성
POST https://api.example.com/users
Content-Type: application/json

{
    "name": "{{name}}",
    "email": "{{email}}"
}

HTTP 201

# 생성된 사용자 조회
GET https://api.example.com/users/{{id}}

HTTP 200
[Asserts]
jsonpath "$.name" equals "{{name}}"
jsonpath "$.email" equals "{{email}}"

Hurl의 고급 기능

조건부 실행

특정 조건이 충족될 때만 요청을 실행하는 예제입니다:

# conditional.hurl
GET https://api.example.com/feature-flags

HTTP 200
[Captures]
new_feature_enabled: jsonpath "$.features.new_feature"

# 새 기능이 활성화된 경우에만 실행
{% if new_feature_enabled == true %}
GET https://api.example.com/new-feature

HTTP 200
{% endif %}

SSL 검증 우회

개발 환경에서 자체 서명된 인증서를 사용할 때 유용합니다:

hurl --insecure api-test.hurl

상세한 로깅

디버깅을 위한 상세 로깅 활성화:

hurl --verbose api-test.hurl

JUnit 형식의 테스트 보고서 생성

CI/CD 파이프라인 통합을 위한 JUnit 형식의 보고서:

hurl --test --report-junit results.xml tests/**/*.hurl

실전 활용 시나리오

시나리오 1: API 회귀 테스트 자동화

개발 과정에서 API 변경으로 인한 회귀를 방지하기 위한 테스트 자동화:

# regression-tests/user-api.hurl
# 사용자 생성
POST https://api.example.com/users
Content-Type: application/json

{
    "name": "Test User",
    "email": "test@example.com"
}

HTTP 201
[Captures]
user_id: jsonpath "$.id"

# 사용자 조회
GET https://api.example.com/users/{{user_id}}

HTTP 200
[Asserts]
jsonpath "$.name" equals "Test User"
jsonpath "$.email" equals "test@example.com"

# 사용자 업데이트
PUT https://api.example.com/users/{{user_id}}
Content-Type: application/json

{
    "name": "Updated User",
    "email": "test@example.com"
}

HTTP 200
[Asserts]
jsonpath "$.name" equals "Updated User"

# 사용자 삭제
DELETE https://api.example.com/users/{{user_id}}

HTTP 204

시나리오 2: 마이크로서비스 통합 테스트

여러 마이크로서비스 간의 통합 테스트:

# integration-tests/order-flow.hurl
# 1. 제품 서비스: 제품 조회
GET {{product_service_url}}/products?category=electronics

HTTP 200
[Captures]
product_id: jsonpath "$.products[0].id"
product_price: jsonpath "$.products[0].price"

# 2. 사용자 서비스: 사용자 인증
POST {{auth_service_url}}/login
Content-Type: application/json

{
    "username": "{{test_username}}",
    "password": "{{test_password}}"
}

HTTP 200
[Captures]
token: jsonpath "$.token"
user_id: jsonpath "$.user_id"

# 3. 장바구니 서비스: 장바구니에 제품 추가
POST {{cart_service_url}}/carts
Authorization: Bearer {{token}}
Content-Type: application/json

{
    "user_id": "{{user_id}}",
    "product_id": "{{product_id}}",
    "quantity": 1
}

HTTP 201
[Captures]
cart_id: jsonpath "$.cart_id"

# 4. 주문 서비스: 주문 생성
POST {{order_service_url}}/orders
Authorization: Bearer {{token}}
Content-Type: application/json

{
    "user_id": "{{user_id}}",
    "cart_id": "{{cart_id}}",
    "total_amount": {{product_price}},
    "shipping_address": {
        "street": "123 Test St",
        "city": "Test City",
        "zipcode": "12345"
    }
}

HTTP 201
[Captures]
order_id: jsonpath "$.order_id"

# 5. 결제 서비스: 결제 처리
POST {{payment_service_url}}/payments
Authorization: Bearer {{token}}
Content-Type: application/json

{
    "order_id": "{{order_id}}",
    "amount": {{product_price}},
    "method": "credit_card",
    "card_details": {
        "number": "4111111111111111",
        "expiry": "12/25",
        "cvv": "123"
    }
}

HTTP 201
[Asserts]
jsonpath "$.status" equals "completed"

# 6. 주문 서비스: 주문 상태 확인
GET {{order_service_url}}/orders/{{order_id}}
Authorization: Bearer {{token}}

HTTP 200
[Asserts]
jsonpath "$.status" equals "paid"
jsonpath "$.payment_status" equals "completed"

시나리오 3: 점진적 배포 검증

카나리 릴리스 또는 블루/그린 배포 검증:

# deployment-validation.hurl
# 현재 프로덕션 환경 검증
GET {{production_url}}/health

HTTP 200
[Asserts]
jsonpath "$.status" equals "ok"
jsonpath "$.version" equals "{{current_version}}"

# 새 배포 환경 검증
GET {{new_deployment_url}}/health

HTTP 200
[Asserts]
jsonpath "$.status" equals "ok"
jsonpath "$.version" equals "{{new_version}}"

# 핵심 기능 검증
GET {{new_deployment_url}}/api/critical-feature

HTTP 200
[Asserts]
jsonpath "$.working" equals true
duration lessThan 1000

Hurl 활용 팁

  1. 파일 구조화: 관련 요청을 하나의 파일로 그룹화하고, 테스트 목적에 따라 폴더를 구성합니다.

  2. 환경 변수 활용: 다양한 환경(개발, 테스트, 프로덕션)에서 실행할 수 있도록 환경 변수를 활용합니다.

  3. CI/CD 통합: 빌드 및 배포 파이프라인에 Hurl 테스트를 통합하여 자동화된 API 검증을 구현합니다.

  4. 테스트 보고서 생성: --report-junit 옵션을 사용하여 CI/CD 도구와 호환되는 테스트 보고서를 생성합니다.

  5. 병렬 실행: 대규모 테스트 스위트의 경우 병렬 실행 스크립트를 작성하여 실행 시간을 단축합니다.

결론

Hurl은 간단한 텍스트 형식의 명령어로 복잡한 HTTP 통신을 테스트하고 자동화할 수 있는 강력한 도구입니다. 이 블로그에서 살펴본 다양한 예제를 통해 API 테스트, 통합 테스트, 배포 검증 등 다양한 시나리오에서 Hurl을 효과적으로 활용할 수 있음을 확인했습니다.

Hurl의 장점은 간결한 문법, 강력한 검증 옵션, 변수 캡처 및 재사용, CI/CD 통합 용이성 등 다양합니다. 이러한 기능을 활용하여 개발자와 QA 엔지니어는 더 효율적이고 안정적인 HTTP 기반 시스템을 구축할 수 있습니다.

참고 자료

Keywords

HTTP Testing Tool, Command-line Tool, API Testing, Text Format, Request Chaining, 응답 검증, 값 캡처, CI/CD 통합, RESTful API, GraphQL, XML 테스트, 마이크로서비스 테스트

728x90
반응형

+ Recent posts