Python 실습 문제 모음

문제 1: 문자열 포맷팅과 템플릿 렌더링

함수를 작성하여 XPath 표현식을 동적으로 생성하고, HTML 템플릿에 변수를 삽입하여 파일로 저장하는 연습입니다.

요구사항

  1. 입력받은 스트를 XPath 표현식 //*[text()='입력값'] 형태로 반환하는 함수 작성
  2. 다음 변수들을 HTML 템플릿에 삽입하여 output.html 파일로 저장 (UTF-8 인코딩)
page_title = "테스트 보고서"
report_title = "API 테스트 결과"
begin_time = "2020-09-10 10:00:00"
elapsed = 3
total_cases = 20
passed = 15
failed = 4
exceptions = 1

템플릿 구조

html_skeleton = '''<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>{page_title}</title></head>
<body>
<h1>{report_title}</h1>
<div>시작 시간: {begin_time} | 소요 시간: {elapsed}초</div>
<div>전체: {total_cases} | 성공: {passed} | 실패: {failed} | 예외: {exceptions}</div>
</body>
</html>'''

구현 예시

def build_xpath(content):
    return f'//*[text()="{content}"]'

def generate_report(template, **context):
    filled = template.format(**context)
    with open('output.html', 'w', encoding='utf-8') as outfile:
        outfile.write(filled)

문제 2: 시퀀스와 매핑 언패킹

튜플과 딕셔너리를 함수 인자로 전달하는 다양한 방법을 연습합니다.

시나리오 A: 튜플 언패킹

locator = ('css selector', '#search-input')

def locate_element(strategy, selector):
    print(f"요소 탐색: {strategy}={selector}")

# locator의 두 값을 locate_element에 전달
locate_element(*locator)

시나리오 B: 딕셔너리 언패킹

db_settings = {
    'hostname': '127.0.0.1',
    'port_number': 3306,
    'account': 'tester',
    'secret': 'secret123',
    'database': 'test_db'
}

def establish_connection(hostname, port_number, account, secret, database):
    print(f"{hostname} 데이터베이스 연결 성공")

# db_settings의 키-값 쌍을 establish_connection에 전달
establish_connection(**db_settings)

문제 3: 클래스를 활용한 상태 공유

Selenium WebDriver 인스턴스를 클래스 속성으로 공유하여 페이지 객체 패턴을 구현합니다.

Page 클래스 설계

from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement

class WebPage:
    def __init__(self, browser: WebDriver):
        self.browser = browser
        self._strategy_map = {
            'id': self.browser.find_element_by_id,
            'name': self.browser.find_element_by_name,
            'class': self.browser.find_element_by_class_name,
            'tag': self.browser.find_element_by_tag_name,
            'link': self.browser.find_element_by_link_text,
            'partial_link': self.browser.find_element_by_partial_link_text,
            'xpath': self.browser.find_element_by_xpath,
            'css': self.browser.find_element_by_css_selector,
        }
    
    def find(self, method: str, expression: str) -> WebElement:
        if method not in self._strategy_map:
            raise ValueError(f"지원하지 않는 탐색 방식: {method}")
        return self._strategy_map[method](expression)
    
    def tap(self, method: str, expression: str) -> None:
        self.find(method, expression).click()
    
    def enter_text(self, method: str, expression: str, content: str) -> None:
        self.find(method, expression).send_keys(content)

사용 예시

from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get('https://www.baidu.com')

page = WebPage(driver)
page.enter_text('id', 'kw', 'Python 자동화')
page.tap('id', 'su')

sleep(3)
driver.quit()

문제 4: CSV 데이터 처리

CSV 파일을 읽고 쓰는 기능을 구현하고, 데이터 기반 테스트를 수행합니다.

파트 A: 데이터 저장

import csv

film_data = [
    ('기생충', '송강호', 'https://parasite.movie'),
    ('인터스텔라', '매튜 맥커너히', 'https://interstellar.movie'),
    ('어벤져스', '로버트 다우니 주니어', 'https://avengers.movie'),
]

columns = ('title', 'lead_actor', 'homepage')

with open('films.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(columns)
    writer.writerows(film_data)

파트 B: 데이터 검증

def calculate_sum(x, y):
    return x + y

with open('test_data.csv', encoding='utf-8') as f:
    reader = csv.reader(f)
    next(reader)  # 헤더 건너뛰기
    for operand_a, operand_b, expected in reader:
        a, b, exp = float(operand_a), float(operand_b), float(expected)
        actual = calculate_sum(a, b)
        status = "통과" if actual == exp else "실패"
        print(f"{a} + {b} = {exp} [{status}]")

문제 5: 효율적인 쌍 탐색

해시 기반 자료구조를 활용하여 시간 복잡도를 개선하는 알고리즘을 구현합니다.

문제 설명

정렬된 배열에서 두 수의 합이 목표값이 되는 인덱스 쌍을 찾습니다. 단순 이중 반복 대신 O(n) 복잡도로 해결해야 합니다.

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
target_sum = 6

# 해시 셋을 활용한 최적화
num_set = set(numbers)
pairs = []

for current in numbers:
    complement = target_sum - current
    if current < complement and complement in num_set:
        left_idx = numbers.index(current)
        right_idx = numbers.index(complement)
        pairs.append((left_idx, right_idx))

print(pairs)  # [(0, 4), (1, 3)]

문제 6: 컴프리헨션 활용

리스트와 딕셔너리 컴프리헨션을 활용한 데이터 변환을 연습합니다.

필터링과 변환

api_response = {
    'status': 0,
    'message': '성공',
    'records': [
        {'name': '봄 세일', 'id': 101, 'state': 1},
        {'name': '여름 세일', 'id': 102, 'state': 2},
        {'name': '가을 세일', 'id': 103, 'state': 0},
        {'name': '겨울 세일', 'id': 104, 'state': 1},
    ]
}

# 진행 중(state=1)인 활동 ID만 문자열로 추출
active_ids = [str(item['id']) for item in api_response['records'] if item['state'] == 1]

딕셔너리 형식 변환

raw_cookies = {'SessionToken': 'xyz789', 'UserID': 'user123'}

selenium_cookies = [
    {'name': key, 'value': val} 
    for key, val in raw_cookies.items()
]

문제 7: 경로 조작과 환경 변수

프로젝트 구조를 기반으로 파일 경로를 구성하고 시스템 환경 변수를 읽습니다.

import os

# 현재 파일 기준 상위 디렉토리 = 프로젝트 루트
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
data_path = os.path.join(project_root, 'data', 'input.csv')

# 환경 변수 조회
db_user = os.getenv('DB_USER', 'default_user')
db_pass = os.getenv('DB_PASSWORD')

문제 8: 메서드 종류

Python 클래스의 세 가지 메서드 유형을 비교합니다.

유형정의 방식호출 방식
인스턴스 메서드def method(self):인스턴스.method()
클래스 메서드@classmethod def method(cls):클래스.method() 또는 인스턴스.method()
정적 메서드@staticmethod def method():클래스.method() 또는 인스턴스.method()

문제 9: INI 설정 파일

configparser를 사용하여 설정 파일을 읽고 적절한 타입으로 변환합니다.

from configparser import ConfigParser

parser = ConfigParser()
parser.read('app.conf')

db_config = dict(parser['database'])
db_config['port'] = int(db_config['port'])
db_config['timeout'] = float(db_config.get('timeout', '30.0'))

문제 10: 이진 탐색

정렬된 배열에서 특정 값의 인덱스를 효율적으로 찾는 알고리즘을 구현합니다.

def binary_search(sorted_arr, goal):
    low, high = 0, len(sorted_arr) - 1
    
    while low <= high:
        mid = (low + high) // 2
        if sorted_arr[mid] == goal:
            return mid
        elif sorted_arr[mid] < goal:
            low = mid + 1
        else:
            high = mid - 1
    return -1

sorted_data = [0, 1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 24, 100]
print(binary_search(sorted_data, 8))  # 6

문제 11: 집합 연산

해시 기반 자료구조의 효율성을 이해하고 집합 연산을 활용합니다.

bucket_a = {('A', 1), ('B', 2), ('C', 3)}
bucket_b = {('A', 1), ('B', 20), ('D', 4)}

only_in_a = bucket_a - bucket_b
only_in_b = bucket_b - bucket_a
common = bucket_a & bucket_b

문제 12: YAML 기반 테스트 자동화

YAML 형식의 테스트 케이스를 파싱하여 Selenium으로 실행합니다.

import yaml
from selenium import webdriver

def execute_step(browser, action, target, val=None):
    handlers = {
        'navigate': lambda: browser.get(target),
        'fill': lambda: browser.find_element(*target.split('=')).send_keys(val),
        'press': lambda: browser.find_element(*target.split('=')).click(),
    }
    handlers[action]()

with open('test_case.yaml', encoding='utf-8') as f:
    case = yaml.safe_load(f)

driver = webdriver.Chrome()
for step in case['steps']:
    execute_step(driver, step['action'], step['target'], step.get('value'))
driver.quit()

문제 13: 로깅 설정

콘솔과 파일에 동시에 출력하는 로거를 구성합니다.

import logging

logger = logging.getLogger('automation')
logger.setLevel(logging.INFO)

console = logging.StreamHandler()
file_handler = logging.FileHandler('execution.log', encoding='utf-8')

formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s', 
                              datefmt='%Y/%m/%d %H:%M:%S')
console.setFormatter(formatter)
file_handler.setFormatter(formatter)

logger.addHandler(console)
logger.addHandler(file_handler)

logger.info("테스트 시작")

문제 14: 쿠키 기반 인증 우회

API로 쿠키를 획득하여 브라우저 세션에 주입합니다.

import requests
from selenium import webdriver

session = requests.Session()
login_resp = session.post('https://example.com/api/login', 
                          json={'user': 'admin', 'pass': 'secret'})

auth_cookie = {'name': 'SESSION_ID', 'value': session.cookies['SESSION_ID']}

browser = webdriver.Chrome()
browser.get('https://example.com/login-page')  # 도메인 설정을 위한 방문
browser.add_cookie(auth_cookie)
browser.get('https://example.com/admin/dashboard')

문제 15-30: 추가 주제

  • 데코레이터: 함수 실행 전후 로깅, 매개변수 검증
  • 날짜 선택기: JavaScript로 readonly 속성 제거 후 입력
  • JSON 처리: 중첩 구조 파싱 및 데이터 추출
  • 이메일 발송: SMTP를 통한 HTML 메일 전송
  • Pytest 확장: 커스텀 명령행 옵션과 훅 함수
  • Excel 조작: openpyxl을 이용한 데이터 기반 테스트
  • 순열 생성: 백트래킹 알고리즘 구현
  • Flask API: 간단한 REST 엔드포인트 구현
  • Behave BDD: Gherkin 문법으로 시나리오 작성
  • 정규표현식: 버전 번호 추출 패턴
  • 병렬 실행: threading을 활용한 다중 브라우저 테스트
  • Bootstrap UI: 반응형 웹 페이지 작성
  • 문자열 알고리즘: 첫 번째 유일 문자 탐색
  • XML 파싱: lxml로 JMeter 테스트 플랜 분석

태그: python selenium webdriver CSV JSON

6월 26일 17:56에 게시됨