JAVA 웹개발 과정 국비 50일차 정리
50일차
※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!
웹 자동화 도구인 Selenium에 대해 배웠다.
1. UI 테스트
1) UI(User Interface) 테스트란?
Frontend 기술로 만들어진 페이지를 테스트 하는 기술
- 사전 필요 지식
- 자바 객체지향 + 라이브러리 활용
- HTML / CSS / JS
- 테스트의 종류
- 수동 테스트 : 사람이 페이지의 요소를 하나하나 테스트 하는 방식
- 자동 테스트 : 개발자가 만들어낸 UI 테스트 어플리케이션으로 테스트 하는 방석
- 테스트 도구
- 네이버 기타 : 사진이미지를 이용 (진입장벽이 낮다. 장난감같은 느낌 - 추천하지 않음)
- Selenium : 전세계적으로 유명한 UI 테스트 라이브러리
2) Selenium을 사용해보자!
① 환경설정
셀레니움을 이용하려면 라이브러리를 다운받아야 할 뿐만 아니라 브라우저 드라이버도 다운받아야한다.
- 구글에 selenium 검색
- 공식 사이트에 들어가서 Downloads 클릭
- 자바 그림 아래 4.0.0버전(21.11월기준)을 다운받는다.
- 라이브러리 폴더에 압축을 풀어서 넣어준다.
- 원하는 프로젝트에 라이브러리를 추가해준다.(selenium jar파일 뿐만 아니라 lib폴더에 들어있는 의존성 라이브러리 파일들도 모두 추가해줘야한다.)
- 구글에 selenium chromedriver 검색
- 다운로드 사이트 들어가기
- 내 브라우저 버전 찾기(우측 상단 … > 도움말 > Chrome 정보)
- 맞는 버전의 드라이버를 다운받는다.
- 압축을 풀어서 exe 파일을 프로젝트에 드래그앤드랍으로 넣어준다.(라이브러리 아래 exe 파일이 추가되면 성공)
② 사용 방법
ⓐ 셀레니움 인스턴스 생성
처음에 셀레니움 인스턴스를 생성해주는 것으로 시작한다.
WebDriver driver = new ChromeDriver();
ⓑ 셀레니움 이동시키기
그리고 만든 셀레니움 인스턴스를 get메소드로 이동시켜준다.
아래와 같이 get 메소드 안에 원하는 페이지 url을 넣으면 셀레니움은 그 페이지를 연다.
driver.get("원하는 페이지 url");
ⓒ 원하는 요소의 주소 찾기
findElement
또는 findElements
를 사용하여 원하는 요소의 주소를 변수에 담아준다.
findElements
는 배열을 리턴하므로 주의한다.
By
뒤에는 여러가지 메소드가 올 수 있는데, id나 class로 찾을 수도 있고, cssSelector를 이용하여 css선택자로 찾을 수도 있고, linkText로 text내용을 찾아서 요소를 가져올 수도 있다.
// id로 찾는 방법
WebElement inputSearch = driver.findElement(By.id("query"));
// class 이름으로 찾는 방법 (배열)
List<WebElement> list = driver.findElements(By.className("btn_import"));
WebElement writeToMe = list.get(0);
// css선택자로 찾는 방법
WebElement mailToMe = driver.findElement(By.cssSelector(".btn_workset>a:nth-child(2)"));
// text 내용으로 찾는 방법
WebElement mailToMe = driver.findElement(By.linkText("내게쓰기"));
이런 저런 방법을 써도 대상을 찾기 힘들 경우에 쓰는 최후의 방법으로는 xpath
메소드가 있다.
원하는 요소의 코드에 우클릭 > 복사 > XPath 복사 > 붙여넣기 를 하면 대상의 경로를 가져올 수 있다.
편리해보이지만 추천하지 않는 이유는 검색속도가 가장 느리기 때문이다.
WebElement mailToMe = driver.findElement(By.xpath(//*[@id="NM_FAVORITE"]/div[1]/ul[1]/li[4]/a))
ⓓ 값 넣기
sendKeys
메소드로 원하는 값을 파라미터에 넣으면 요소에 값을 쉽게 넣을 수 있다.
특정 사이트에서는 이 메소드로 값을 넣게되면 bot으로 인식하는 경우도 있으니 주의해야한다.
// 검색창 input 태그를 요소로 잡아 Selenium 검색
inputSearch.sendKeys("Selenium");
다른 방법으로는 자바스크립트를 이용하여 넣는 방법이 있다.
JavascriptExecutor
는 셀레니움이 자바스크립트를 실행할 수 있게 지원하는 클래스이다.
executeScript
메소드에 js로 요소의 value값을 선택한다.
arguments[index]
는 쉽게 말하면 JDBC의 preparedStatement의 쿼리문의 ? 역할을 해준다고 생각하면 된다. 뒤쪽에 파라미터를 이어 붙이면 0번, 1번, 2번… 이렇게 값을 넣어줄 수 있다.
이 방식은 sendkeys
처럼 특정 키를 눌러 입력하는 것으로 인식하지 않고, 복사-붙여넣기로 인식하기 때문에 bot으로 인식하지 못한다.
JavascriptExecutor script = (JavascriptExecutor)driver;
script.executeScript("document.getElementById('id').value=arguments[0]", "Test");
ⓔ 클릭하기
클릭은 click
메소드를 이용하면 간단하다.
WebElement btnSearch = driver.findElement(By.id("search_btn"));
btnSearch.click();
ⓕ iframe
웹페이지를 개발자도구로 뜯어보다보면 iframe 태그로 감싸져있는 부분이 존재하는 경우가 있다.
iframe 태그는 내 페이지에 다른 페이지를 가져오게 해준다.
태그 자체가 보안적 위협을 많이 가지고 있어 다른 사이트를 가져오면 대부분 블락을 해놓은 경우가 많다.
따라서 보통은 다른 사람의 페이지보다는 내 페이지를 가져오는 식으로 사용한다.
이 태그는 html, body 태그가 또 들어있는 구조이기 때문에 셀레니움이 바깥쪽 페이지를 보고 있을 때 iframe 안쪽의 요소를 선택하면 id를 찾지 못하는 오류가 발생한다.
이때, switchTo().frame
메소드를 사용하여 셀레니움이 안쪽(iframe)을 보도록 만들어주면 된다.
그러나 마찬가지로 바깥쪽에 있는 요소는 건드릴 수 없게 된다.
driver.switchTo().frame("loginIframe");
ⓖ 셀레니움 대기하게 하기
컴퓨터의 성능에 따라 동작 후 로딩 시간이 걸리게 되는데, 로딩이 완료된 후에 셀레니움을 동작하게 하지 않으면 에러가 나기가 쉽다.
Thread.sleep(밀리초)
로 코드의 실행 속도를 늦출 수는 있지만, 시간을 얼마나 줘야 로딩이 끝나는지, 에러인지 아닌지 판단하기는 쉽지 않다.
WebDriverWait
클래스는 시간을 적어주는 것이 아니라 어떤 상황이 될 때까지 셀레니움을 대기시킨다.
Duration.ofSeconds
의 파라미터인 10
은 대기가 10초를 넘기면 에러를 발생시키라는 뜻이다.
ExpectedConditions
뒤에는 무수히 많은 상황을 담은 메소드가 존재하니 필요한 메소드를 찾아서 적재적소에 활용하자!
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
wait.until(ExpectedConditions.persenceOfElementLocated(By.id("subject"));)
3) 자주 보는 오류
① NoSuchElementException
말 그대로 요소를 찾지 못해서 뜨는 에러이다.
원인은 크게 세가지로 볼 수 있다.
- 정말로 그 요소가 존재하지 않을 때, 또는 오타일 때
- iframe 안에 있는 요소를 검색했으나 셀레니움은 바깥의 페이지를 보고 있을 때
- 요소가 로딩 되기 전에 셀레니움이 요소를 먼저 찾으려고 시도했을 때
② ElementNotInteractableException
요소에 어떤 동작(클릭 등)을 적용하려고 했으나 그 요소가 숨어있거나 기타 다른 상황으로 인하여 동작을 진행할 수 없을 때 발생하는 에러이다.
③ StaleElementReferenceException
셀레니움을 쓰면서 많이 겪는 에러라고 한다. 잘 알아두어야겠다.
stale
은 오래된, 낡은, 퀴퀴한 이라는 뜻으로, 직역하면 오래된 요소를 참조하려고 했음!!
즉, 지나간 페이지의 요소를 참조하려고 해서 생긴 에러이다.
예를 들면, 네이버 메인의 a 태그의 링크를 배열로 모은 리스트를 for문을 돌려가며 클릭하는 코드가 있을 때, 셀레니움은 첫번째 a 태그를 클릭하여 그 태그의 페이지로 이동할 것이다. 이때 원래 있었던 for문의 요소들은 오래된 요소가 되버리면서 이 에러가 발생하는 것이다.
4) 네이버 자동로그인 후 내게 메일 쓰기 - 예제
네이버 로그인 창에 아이디, 비밀번호를 쓰고 로그인을 한 뒤, 메일 페이지에 들어가서 내게 쓰기 버튼을 클릭한 후 제목에 “웹 자동화 연습 중 입니다…“를 써보는 실습을 했다.
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class quiz02 {
public static void main(String[] args) throws Exception {
// 셀레니움 인스턴스 생성
WebDriver driver = new ChromeDriver();
// 셀레니움 대기시키는 인스턴스 생성
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
// 자바스크립트 실행 가능하게 하기
JavascriptExecutor script = (JavascriptExecutor)driver;
// 셀레니움 네이버 로그인 페이지로 이동
driver.get("https://nid.naver.com/nidlogin.login?mode=form&url=https%3A%2F%2Fwww.naver.com");
// 아이디, 비밀번호 입력 (js이용)
script.executeScript("document.getElementById('id').value=arguments[0]", "id");
script.executeScript("document.getElementById('pw').value=arguments[0]", "pw");
// 로그인 버튼 클릭
WebElement loginBtn = driver.findElement(By.id("log.login"));
loginBtn.click();
// '내게쓰기' 버튼을 찾을 때 까지 대기
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("subject")));
// 제목에 "웹 자동화 연습 중 입니다..." 입력
WebElement subject = driver.findElement(By.id("subject"));
subject.sendKeys("웹 자동화 연습 중 입니다...");
// 지연 시간 주기
Thread.sleep(5000);
// 셀레니움 종료
driver.close();
}
}
댓글남기기