2019년 12월 5일 목요일

Selenium implicitly-wait and explicitly-wait

implicitly-wait : 브라우져 전체 요소가 로드될 때 까지 기다린다.
explicitly-wait : 특정 요소가 로드될 때 까지 기다린다.

implicitly wait
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class WaitTest {

 private WebDriver driver;
 private String baseUrl;
 private WebElement element;

 @BeforeMethod
 public void setUp() throws Exception {
  driver = new FirefoxDriver();
  baseUrl = "http://www.google.com";
  driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
 }

 @Test
 public void testUntitled() throws Exception {
  driver.get(baseUrl);
  element = driver.findElement(By.id("lst-ib"));
  element.sendKeys("Selenium WebDriver Interview questions");
  element.sendKeys(Keys.RETURN);
  List<WebElement> list = driver.findElements(By.className("_Rm"));
  System.out.println(list.size());
 }

 @AfterMethod
 public void tearDown() throws Exception {
  driver.quit();
 }
}


Explicitly wate
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class ExpectedConditionExample {
 // created reference variable for WebDriver
 WebDriver driver;

 @BeforeMethod
 public void setup() throws InterruptedException {
  // initializing driver variable using FirefoxDriver
  driver=new FirefoxDriver();
  // launching gmail.com on the browser
  driver.get("https://gmail.com");
  // maximized the browser window
  driver.manage().window().maximize();
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
 }

 @Test
 public void test() throws InterruptedException {
  // saving the GUI element reference into a "element" variable of WebElement type
  WebElement element = driver.findElement(By.id("Email"));
  // entering username
  element.sendKeys("dummy@gmail.com");
  element.sendKeys(Keys.RETURN);
  // entering password
  driver.findElement(By.id("Passwd")).sendKeys("password");
  // clicking signin button
  driver.findElement(By.id("signIn")).click();
  // explicit wait - to wait for the compose button to be click-able
  WebDriverWait wait = new WebDriverWait(driver,30);
  wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[contains(text(),'COMPOSE')]")));
  // click on the compose button as soon as the "compose" button is visible
  driver.findElement(By.xpath("//div[contains(text(),'COMPOSE')]")).click();
 }

 @AfterMethod
 public void teardown() {
  // closes all the browser windows opened by web driver
  driver.quit();
 }
}


Fluent wait
1
2
3
4
5
6
7
8
9
Wait wait = new FluentWait(WebDriver reference)
.withTimeout(timeout, SECONDS)
.pollingEvery(timeout, SECONDS)
.ignoring(Exception.class);

WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
 public WebElement applyy(WebDriver driver) {
 return driver.findElement(By.id("foo"));
}});

2019년 12월 2일 월요일

Jenkins 관련 내용

Windows Jenkins settings.xml 파일 위치
=> C:\Windows\System32\config\systemprofile\.m2

외부 리포트 파일의 css 적용되지 않을 경우
=> jenkins.xml에 "-Dhudson.model.DirectoryBrowserSupport.CSP=" 추가하기

2019년 11월 28일 목요일

REST API의 개념

REST의 정의

"REpresentational State Transfer"로서 자원(resource)을 이름(표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미한다.
자원(resource)의 표현(representation)은
자원(resource) : 해당 소프트웨어가 관리하는 모든 것(문서, 그림, 데이터 등등)
표현(representation) : 자원을 표현하기 위한 이름(회원 정보가 자원이라면 'member'를 자원의 표현으로 정하는 것)
상태(정보) 전달은 데이터가 요청되는 시점에 자원의 상태(정보)를 전달한다.
Json 혹은 XML로 데이터를 주고 받는다.

REST API는??

API(Application Programming Interface) : 데이터와 기능의 집합을 제공하여 컴퓨터 프로그램 간 상호작용을 촉진하며, 서로 정보를 교환 가능하도록 하는 것을 말한다.
그래서 REST API는 REST 기반으로 서비스 API를 구현한 것이다.

REST API 설계 규칙

  1. 슬래시 구분자( / ) 는 계층 관계를 나타내는데 사용한다.
    예: http://sample.com/home/login
  2. URI 마지막 문자로 슬래시( / )를 포함하지 않는다.
    예: httpL//sample.com/home/login/ ( X )
  3. 하이픈( - ) 은 URI 가독성을 높이는데 사용한다.
  4. 밑줄( _ ) 은 URI에 사용하지 않는다.
  5. URI 경로에는 소문자
  6. 파일확장자는 URI에 포함하지 않는다.

그러면 RESTful API는 뭐지???

REST가 위에서 설명한 것과 같다면 RESTful은 REST라는 아키텍쳐를 구현하는 웹 서비스를 나타내기 위해 사용되는 용어이다.
'REST API'를 제공하는 웹서비스를 'RESTful'하다고 할 수 있다. 즉, REST 원리를 따르는 시스템은 RESTful이란 용어로 지칭한다.

HTTP Method

HTTP Method
전송 형태
설명
GET
GET [request-uri]?query_string HTTP/1.1
Host:[Hostname] 혹은 [IP]
요청받은 URI의 정보를 검색하여 응답
POST
POST [request-uri] HTTP/1.1
Host:[Hostname] 혹은 [IP]
Content-Lenght:[Length in Bytes]
Content-Type:[Content Type]
[데이터]
요청된 자원을 생성한다.
PUT
PUT [request-uri] HTTP/1.1
Host:[Hostname] 혹은 [IP]
Content-Lenght:[Length in Bytes]
Content-Type:[Content Type]
[데이터]
요청된 자원을 수정(UPDATE)한다.
DELETE
DELETE [request-uri] HTTP/1.1
Host:[Hostname] 혹은 [IP]
요청된 자원을 삭제할 것을 요청
PATCH
PATCH [request-uri] HTTP/1.1
Host:[Hostname] 혹은 [IP]
Content-Lenght:[Length in Bytes]
Content-Type:[Content Type]
[데이터]
PUT과 유사하게 요청된 자원을 수정(UPDATE)할 때 사용.
PUT의 경우 자원 전체를 갱신하는 의미지만,
PATCH는 해당 자원의 일부를 교체하는 의미로 사용

Content-Type

해당 개체에 포함되는 미디어 타입 정보를 말하며 응답 내에 있는 Content-Type 헤더는 클라이언트에게 반환된 컨텐츠의 컨텐츠 유형이 실제로 무엇인지를 알려준다.
컨텐츠의 타입(MIME 미디어 타입)과 문자 인코딩 방식(EUC-KR, UTF-8등)을 지정한다.

문법
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=somthing

HTTP code

응답 대역
응답 코드
설명
성공200OK

201Created
PUT 메소드에 의해 원격지 서버에 파일 생성됨

203서버가 클라이언트 요구 중 일부만 전송

204No content
요구한 데이터를 변경된 타 URL에 요청함 / Redirect된 경우
클라이언트
요청 에러
400Bad Request
사용자의 잘못된 요청을 처리할 수 없음

401인증이 필요한 페이지를 요청한 경우

403접근 금지

404Not found
요청한 페이지 없음

405허용되지 않는 http method 사용함

408요청 시간 초과

410영구적으로 사용 금지

412전체 조건 실패

414요청URL길이가 긴 경우
서버에러500내부 서버 오류

501웹 서버가 처리할 수 없음

503서비스 제공 불가

504Gateway timeout
게이트웨이 시간 초과

505해당 http 버전 지원되지 않음

URL과 URI의 의미
  1. URL(Uniform Resource Locator) : 통합 자원 지시자
    1. 예를 들어 http://test.com/work/test.pdf 는 test.com 서버에서 work 폴더 안의 test.pdf를 요청하는 URL을 의미한다.
  2. URI(Unitform Resource Identifier) : 통합 자원 식별자
    1. 프로토콜 + : + // + 호스트이름 + 주소 → http://test.com
    2. 자원에 접근하기 위해 사용되는 절차
    3. 어떤 자원을 가지고 있는 특정한 컴퓨터
    4. 컴퓨터 상의 유니크한 자원의 이름(파일명)
  3. URN(Uniform Resource Name) : 리소스의 위치와 상관없이 리소스의 이름값을 이용하여 접근하는 방식

URI
URNURL
test.com/test.htmlhttps://test.com/test.html
test2.com/image.pngftp://test2.com.file.pdf
URI >= URL, URN


2019년 10월 2일 수요일

jenkins pre build, post build 시 execute shell 추가할 때 해당 부분이 문제가 있어 빌드 실패가 된다면?


해당 execute shell 명령에서 문제가 생길 경우 build fail이 발생한다.
이를 해결하기 위해서는 아래와 같은 명령어를 추가한다.


  • 명령 실패 시 추가 실행을 중지하려면
    • command || exit 0

  • 명령이 실패할 때 실행을 계속하려면
    • command || true

2019년 7월 18일 목요일

API Test 진행 시 profile 선택 관련 정리 - Maven profile, yaml, lombok

1. jenkins에서 profile 선택하여 빌드 및 테스트 수행
mvn clean test -P ${evn}
env : env는 jenkins의 string parameter나 choice parameter를 이용한다.
ex) evn = qa or release or stage

2. intelliJ에서는

3. 프로파일별 테스트 데이터 관리는 yaml 파일로 관리한다.
 
 yaml file 위치

testdata.yaml
userId : test
password : qwe123

TestData.java
TestData.java는 lombok library를 이용하여 코드를 간결화 한다.
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.yaml.snakeyaml.Yaml;

import java.io.InputStream;

@Getter 
@Setter
public class TestData {
 private String userId;
 private String password;

 @Override
 public String toString() {
  return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
 }

 public TestData getTestData() {
  Yaml yaml = new Yaml();
  InputStream inputStream = TestData.class.getResourceAsStream("/testdata.yaml");
  return yaml.loadAs(inputStream, TestData.class);
 }
}

사용법

TestData testData = new TestData();
testData = testData.getTestData();
RestAssured.baseURI = testData.getTargetURL();

2019년 7월 8일 월요일

TestNG에 ExtentReport 적용하기

1. pom.xml dependency 추가

<dependency>    
  <groupId>com.aventstack</groupId>    
  <artifactId>extentreports</artifactId>    
  <version>3.1.5</version>
</dependency>

2. ExtentManager 추가

public class ExtentManager {
    private static ExtentReports extent;

    public static ExtentReports getInstance() {
        if (extent == null)
            createInstance();
        return extent;
    }

    //Create an extent report instance
    public static ExtentReports createInstance() {
        String reportFile = new File("target/result.html").getAbsolutePath();
        ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(reportFile);
        htmlReporter.setAppendExisting(true);
        htmlReporter.config().setTestViewChartLocation(ChartLocation.BOTTOM);
        htmlReporter.config().setChartVisibilityOnOpen(true);
        htmlReporter.config().setTheme(Theme.STANDARD);
        htmlReporter.config().setDocumentTitle(reportFile);
        htmlReporter.config().setEncoding("UTF-8");
        htmlReporter.config().setReportName(reportFile);

        extent = new ExtentReports();
        extent.attachReporter(htmlReporter);
        extent.setSystemInfo("Environment", "QA");
        TestData testData = new TestData();
        extent.setSystemInfo("Host Name", testData.getTestData().getUri());
        return extent;
    }
}

3. TestListener 추가

public class TestListner implements ITestListener {
    //Extent Report Declarations
    private static final Logger logger = LoggerFactory.getLogger(TestListner.class);
    private static ExtentReports extent = ExtentManager.createInstance();
    private static ThreadLocal<ExtentTest> test = new ThreadLocal<>();

    @Override
    public synchronized void onStart(ITestContext context) {
        logger.debug("Test Suite started!");
    }

    @Override
    public synchronized void onFinish(ITestContext context) {
        logger.debug("Test Suite is finished!");
        extent.flush();
    }

    @Override
    public synchronized void onTestStart(ITestResult result) {
        logger.debug(result.getMethod().getMethodName() + " started!");
        ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName(),result.getMethod().getDescription());
        extentTest.assignCategory(result.getTestClass().getRealClass().getSimpleName());
        test.set(extentTest);
    }

    @Override
    public synchronized void onTestSuccess(ITestResult result) {
        logger.debug(result.getMethod().getMethodName() + " passed!");
        test.get().pass("Test passed");
    }

    @Override
    public synchronized void onTestFailure(ITestResult result) {
        logger.debug(result.getMethod().getMethodName() + " failed!");
        test.get().fail(result.getThrowable());
    }

    @Override
    public synchronized void onTestSkipped(ITestResult result) {
        logger.debug(result.getMethod().getMethodName() + " skipped!");
        test.get().skip(result.getThrowable());
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
        logger.debug("onTestFailedButWithinSuccessPercentage for " + result.getMethod().getMethodName());
    }
}

4. testng.xml에 추가
<suite name="TestNG Suite Name">
    <listeners>
        <listener class-name="com.xxxx.utils.listners.TestListner" />    
    </listeners>
    <test name="full_test">
         <packages>
             <package name="com.xxx.test.*" />
         </packages>
     </test>
</suite>

2019년 7월 2일 화요일

Jenkins Parameter를 java code로 받아오는 방법

1. Jenkins 구성에서 General탭의 "이 빌드는 매개변수가 있습니다." 체크
2. String parameter 등의 매개변수 추가
3. Build 옵션에서 Goal and options에 추가한 파라메터를 추가
-> clean test -D자바코드에서사용할파라메타=$젠킨스에서추가한파라메타
=> ex) clean test -DdeviceName=$deviceName -Dversion=$version

4. Java code에서는
String DEVICENAME = System.getProperty("deviceName");
String VERSION = System.getProperty("version");

2019년 6월 28일 금요일

Jenkins API를 이용한 원격 빌드 방법

시나리오
1) 해당 레포지토리를 빌드하는 Jenkins(A)와 API Test를 하는 Test용 Jenkins(B)가 있다.
2) A에서 빌드가 완료되고 서버의 인스턴스가 올라오면 B에서 테스트가 자동으로 시작된다.
즉, 물리적인 장비가 다르다.

위 시나리오에 맞춰 Jenkins를 구성할 때 아래의 방법을 이용한다.

1. B에서 해당 계정(빌드를 수행할 계정)의 API Token을 얻어온다.
  • http://JENKINS_URL/me/configure 에 접속
  • API Token 란의 show Legacy API Token 클릭(add new token 해도 된다.)
2. A에서 Post Step 란에 Excute Shell을 클릭하고 아래의 URL을 입력한다.
  • http://JENKINS_URL/job/JOBNAME/build or http://JENKINS_URL/job/JOBNAME/buildWithParameters
  • /build 와 /buildWithParameters의 차이 : 빌드 시 parameter 유무
  • ex: curl -d  "branch=master&env=qa" http://JENKINS_URL/job/JOBNAME/buildWithParameters?token=API_TOKEN
3. B에서 빌드 유발에서 "빌드를 원격으로 유발" 클릭하고 Authentication Token에 API Token을 입력한다.