
Selenium WebDriver를 생각할 때, 일반적으로 브라우저 자동화 및 UI 테스트와 연관됩니다. 그러나 Selenium은 올바르게 사용하면 API 테스트를 위한 강력한 도구가 될 수 있습니다. 이 튜토리얼에서는 Selenium WebDriver의 기능을 활용하여 API 테스트를 수행하는 방법을 안내하며, 실용적인 예제와 최선의 관행을 제공합니다.
API(Application Programming Interface) 테스트는 애플리케이션의 API를 직접 테스트하여 기능, 신뢰성, 성능, 보안을 검증하는 과정을 포함합니다. Postman, REST Assured 또는 SoapUI와 같은 API 테스트를 위한 전용 도구가 있지만, Selenium WebDriver는 UI 테스트와 API 테스트를 동일한 프레임워크에서 결합하고자 할 때 API 테스트 도구에 유용한 추가 기능이 될 수 있습니다.
전제 조건
Selenium WebDriver를 사용하여 API 테스트를 시작하기 전에 다음을 확인하세요:
- Selenium WebDriver에 대한 기본 지식
- 선택한 프로그래밍 언어 (Java, Python, C#, JavaScript)
- 개발 환경에 Selenium WebDriver 설정 완료
- REST/SOAP API 이해
- HTTP 메서드(GET, POST, PUT, DELETE)에 대한 기본 지식
아키텍처 이해
Selenium WebDriver의 아키텍처는 다음과 같은 API 테스트에 적합한 기능을 제공합니다:
- 내장 라이브러리나 외부 라이브러리를 사용하여 HTTP 요청을 직접 전송
- 응답을 처리하고 데이터를 검증
- 기존 테스트 프레임워크와 통합
- 테스트 데이터 및 환경 관리
환경 설정하기
Selenium WebDriver로 API 테스트를 위한 기본 환경을 설정해 보겠습니다:
Java 예제
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class SeleniumApiTesting {
private WebDriver driver;
public void setUp() {
System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless"); // API 테스트를 위한 헤드리스 모드
driver = new ChromeDriver(options);
}
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Python 예제
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import requests
import json
def setup_driver():
chrome_options = Options()
chrome_options.add_argument("--headless") # API 테스트를 위한 헤드리스 모드
driver = webdriver.Chrome(options=chrome_options)
return driver
def teardown_driver(driver):
if driver is not None:
driver.quit()
Selenium WebDriver를 활용한 API 테스트 접근 방식
1. 기본 HTTP 라이브러리 사용하기
가장 간단한 접근 방식은 Selenium WebDriver와 함께 프로그래밍 언어의 기본 HTTP 라이브러리를 사용하는 것입니다.
Java 예제 - GET 요청
public String performGetRequest(String endpoint) throws IOException {
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
System.out.println("GET 응답 코드: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
} else {
return "GET 요청이 응답 코드로 실패했습니다: " + responseCode;
}
}
Python 예제 - POST 요청
def perform_post_request(endpoint, payload):
headers = {'Content-Type': 'application/json'}
response = requests.post(endpoint, data=json.dumps(payload), headers=headers)
print(f"POST 응답 코드: {response.status_code}")
if response.status_code == 200:
return response.json()
else:
return f"POST 요청이 응답 코드로 실패했습니다: {response.status_code}"
2. JavaScriptExecutor를 사용하여 AJAX 호출
또 다른 접근 방식은 Selenium의 JavaScriptExecutor를 사용하여 브라우저에서 직접 AJAX 호출을 하는 것입니다.
Java 예제
import org.openqa.selenium.JavascriptExecutor;
public String performApiCallWithJsExecutor(String endpoint, String method, String payload) {
String script = String.format(
"var xhr = new XMLHttpRequest();" +
"xhr.open('%s', '%s', false);" +
"xhr.setRequestHeader('Content-Type', 'application/json');" +
"xhr.send('%s');" +
"return xhr.responseText;",
method, endpoint, payload
);
return (String) ((JavascriptExecutor) driver).executeScript(script);
}
Python 예제
def perform_api_call_with_js_executor(driver, endpoint, method, payload):
script = f"""
var xhr = new XMLHttpRequest();
xhr.open('{method}', '{endpoint}', false);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send('{payload}');
return xhr.responseText;
"""
return driver.execute_script(script)
3. API 호출 가로채기 및 수정하기
Selenium WebDriver는 애플리케이션이 수행하는 API 호출을 가로채고 수정하는 데 사용할 수 있으며, 특히 BrowserMob Proxy와 같은 프록시 도구와 결합할 때 유용합니다.
BrowserMob Proxy와 함께하는 Java 예제
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import org.openqa.selenium.Proxy;
public void setupProxyForApiInterception() {
// 프록시 시작
BrowserMobProxy proxy = new BrowserMobProxyServer();
proxy.start(0);
// Selenium 프록시 객체 가져오기
Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
// Chrome을 프록시를 사용하도록 구성
ChromeOptions options = new ChromeOptions();
options.setCapability("proxy", seleniumProxy);
// WebDriver 인스턴스 생성
driver = new ChromeDriver(options);
// API 호출을 가로채기 위해 요청 필터 추가
proxy.addRequestFilter((request, contents, messageInfo) -> {
if (request.getUri().contains("/api/")) {
System.out.println("가로챈 API 호출: " + request.getUri());
// 필요에 따라 헤더, 매개변수 또는 요청 본체 수정
}
return null;
});
// 응답 필터를 추가하여 API 응답을 검사하고 수정
proxy.addResponseFilter((response, contents, messageInfo) -> {
if (messageInfo.getOriginalRequest().getUri().contains("/api/")) {
String responseBody = contents.getTextContents();
System.out.println("API 응답: " + responseBody);
// 필요에 따라 응답 수정
}
});
}
완전한 API 테스트 프레임워크 구축하기
Selenium WebDriver를 사용하여 더 구조화된 API 테스트 프레임워크를 만들어 보겠습니다:
Java 예제
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.IOException;
public class ApiTestFramework {
private WebDriver driver;
private final String BASE_URL = "<https://api.example.com>";
@BeforeClass
public void setUp() {
System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
driver = new ChromeDriver(options);
}
@Test
public void testGetUserEndpoint() throws IOException {
String endpoint = BASE_URL + "/api/users/1";
String response = performGetRequest(endpoint);
JSONObject jsonResponse = new JSONObject(response);
Assert.assertEquals(jsonResponse.getString("name"), "John Doe");
Assert.assertEquals(jsonResponse.getInt("id"), 1);
Assert.assertTrue(jsonResponse.has("email"));
}
@Test
public void testCreateUserEndpoint() throws IOException {
String endpoint = BASE_URL + "/api/users";
JSONObject payload = new JSONObject();
payload.put("name", "Jane Smith");
payload.put("email", "jane.smith@example.com");
String response = performPostRequest(endpoint, payload.toString());
JSONObject jsonResponse = new JSONObject(response);
Assert.assertTrue(jsonResponse.has("id"));
Assert.assertEquals(jsonResponse.getString("name"), "Jane Smith");
}
private String performGetRequest(String endpoint) throws IOException {
// 이전 예제의 구현
}
private String performPostRequest(String endpoint, String payload) throws IOException {
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
// 페이로드를 연결에 작성
try (java.io.OutputStream os = connection.getOutputStream()) {
byte[] input = payload.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
System.out.println("POST 응답 코드: " + responseCode);
try (BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
}
}
@AfterClass
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Python 예제
import unittest
import json
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import requests
class ApiTestFramework(unittest.TestCase):
BASE_URL = "<https://api.example.com>"
def setUp(self):
chrome_options = Options()
chrome_options.add_argument("--headless")
self.driver = webdriver.Chrome(options=chrome_options)
def test_get_user_endpoint(self):
endpoint = self.BASE_URL + "/api/users/1"
response = self.perform_get_request(endpoint)
self.assertEqual(response['name'], "John Doe")
self.assertEqual(response['id'], 1)
self.assertIn('email', response)
def test_create_user_endpoint(self):
endpoint = self.BASE_URL + "/api/users"
payload = {
"name": "Jane Smith",
"email": "jane.smith@example.com"
}
response = self.perform_post_request(endpoint, payload)
self.assertIn('id', response)
self.assertEqual(response['name'], "Jane Smith")
def perform_get_request(self, endpoint):
response = requests.get(endpoint)
return response.json() if response.status_code == 200 else None
def perform_post_request(self, endpoint, payload):
headers = {'Content-Type': 'application/json'}
response = requests.post(endpoint, data=json.dumps(payload), headers=headers)
return response.json() if response.status_code in [200, 201] else None
def tearDown(self):
if self.driver:
self.driver.quit()
if __name__ == '__main__':
unittest.main()
UI 및 API 테스트 결합하기
Selenium WebDriver를 API 테스트에 사용하는 가장 큰 장점 중 하나는 UI 및 API 테스트를 동일한 프레임워크에서 결합할 수 있다는 것입니다:
@Test
public void testLoginAndVerifyUserDataAPI() throws IOException {
// UI 부분: UI를 통해 로그인
driver.get("<https://example.com/login>");
driver.findElement(By.id("username")).sendKeys("testuser");
driver.findElement(By.id("password")).sendKeys("password");
driver.findElement(By.id("loginButton")).click();
// 로그인 완료를 기다림
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.urlContains("/dashboard"));
// 쿠키 또는 로컬 저장소에서 인증 토큰 추출
String authToken = (String) ((JavascriptExecutor) driver)
.executeScript("return localStorage.getItem('authToken');");
// API 부분: 토큰을 사용하여 인증된 API 호출 수행
String endpoint = BASE_URL + "/api/user/profile";
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + authToken);
// API 응답 처리 및 검증
int responseCode = connection.getResponseCode();
Assert.assertEquals(responseCode, 200);
// 응답 읽기 및 파싱
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = in.lines().collect(Collectors.joining());
in.close();
JSONObject jsonResponse = new JSONObject(response);
// API 데이터와 UI에 표시된 데이터 검증
String uiUsername = driver.findElement(By.id("profileUsername")).getText();
Assert.assertEquals(jsonResponse.getString("username"), uiUsername);
}
Selenium WebDriver로 API 테스트를 위한 모범 사례
- 헤드리스 모드 사용: 순수 API 테스트를 수행할 때 리소스를 절약하기 위해 Selenium을 헤드리스 모드로 실행하세요.
- API 테스트와 UI 테스트 분리: 결합할 수 있지만 API 테스트와 UI 테스트는 논리적으로 분리하세요.
- 어설션 라이브러리 활용: API 응답을 검증하기 위한 종합 어설션 라이브러리를 사용하세요.
- 오류 처리 구현: API 실패를 위한 적절한 오류 처리를 추가하세요.
- API 요청 및 응답 로깅: 디버깅을 위해 모든 API 상호 작용을 로깅하세요.
- 테스트 매개변수화: 다양한 시나리오를 테스트하기 위해 데이터 제공자 또는 파라미터화된 테스트를 사용하세요.
- 인증 처리 구현: 인증을 처리하기 위한 재사용 가능한 메서드를 만드세요.
- 성능 고려: Selenium은 전용 API 테스트 도구에 비해 오버헤드를 추가할 수 있습니다.
Selenium WebDriver를 API 테스트에 사용하는 제한 사항
- 성능 오버헤드: Selenium은 주로 브라우저 자동화를 위해 설계되었으므로 순수 API 테스트에는 오버헤드를 추가합니다.
- 제한된 API 전용 기능: 전용 API 테스트 도구는 더 많은 특정 기능을 제공합니다.
- 브라우저 의존성: 헤드리스 모드에서도 Selenium은 브라우저가 필요하므로 API 테스트에는 불필요할 수 있습니다.
- 복잡성: API 테스트를 위한 Selenium 설정은 전용 API 테스트 도구를 사용하는 것보다 더 복잡할 수 있습니다.
API 테스트에 Selenium WebDriver를 사용할 때
Selenium WebDriver는 다음과 같은 상황에서 API 테스트에 가장 적합합니다:
- Selenium 기반 UI 테스트 프레임워크가 이미 있고 이를 확장하고자 할 때.
- UI 및 API 상호 작용이 포함된 시나리오를 테스트해야 할 때.
- 브라우저의 맥락에서 API를 테스트해야 할 때(예: JavaScript API 호출 테스트).
- 애플리케이션에서 수행하는 API 호출을 가로채고 수정하려고 할 때.
결론
Selenium WebDriver는 API 테스트를 위한 다용도 도구가 될 수 있으며, 특히 기존 UI 테스트 프레임워크와 통합할 때 유용합니다. 복잡한 API 테스트 필요성을 위해 전용 API 테스트 도구를 대체할 수는 없지만, UI 테스트와 API 테스트를 단일 프레임워크에서 결합하는 유연한 방법을 제공합니다.
이 튜토리얼에서 제공하는 접근 방식과 예제를 활용하여 Selenium WebDriver를 API 테스트 요구 사항에 효과적으로 사용할 수 있습니다. 트레이드오프를 고려하고 특정 테스트 요구에 맞는 적절한 도구를 선택하세요.
REST API, SOAP 서비스 또는 GraphQL 엔드포인트를 테스트할 때, Selenium WebDriver는 응용 프로그램의 UI와 기본 API 기능을 모두 검증하는 포괄적인 테스트를 생성하는 데 도움이 됩니다.
더 고급 API 테스트 필요를 위해 Selenium WebDriver를 전용 API 테스트 라이브러리나 REST Assured(자바) 또는 Requests(파이썬)와 결합하여 두 세계의 장점을 모두 얻는 것을 고려할 수 있습니다.
테스트가 잘 되길 바랍니다!