[JAVA #16] [Web Automation #16] Selenium With TestNG #5 Parallel Execution [KR]

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@june0620·
0.000 HBD
[JAVA #16] [Web Automation #16] Selenium With TestNG #5 Parallel Execution [KR]
![redsjavahouse1591357_1280.jpg](https://files.steempeak.com/file/steempeak/june0620/DKldjbG3-reds-java-house-1591357_1280.jpg)
image source: [pixabay](https://pixabay.com)
***

TestNG의 여러 브라우저를 동시에 컨트롤할 수 있는 병렬 테스트를 지원한다. 
QA를 하다보면 제일 번거롭고 리소스가 많이 드는 것이 바로 브라우저별 테스트다. 
요즘 많은 회사가 크로미움 기반으로 브라우저를 개발하지만 QA는 아직도 IE10, IE11, FireFox, Chrome, Safari 등 브라우저를 테스트해야 한다. 너무 번거롭다. 그냥 Chrome이 다 독점해 버렸으면 하는 그릇된 생각도 든다. ㅎㅎㅎ
자동화도 마찬가지이다. 자동화의 목적이 사람이 하기 싫은 거, 사람보다 더 잘 할수 있는 거이기 때문에 여러 브라우저를 테스트할 필요가 있다. 

TestNG의 parallel test와 Selenium의 DesiredCapabilities 클래스로 다중 브라우저 테스트를 할수 있다. 
그럼 지금까지의 코드를 Chrome과 FireFox에서 동시에 돌려보자. 아래는 `AS-IS` 코드다.

```
package com.steem.webatuo;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

import java.util.List;
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.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class Steemit {
    WebDriver driver;
    String baseUrl = "https://steemit.com";
    @BeforeClass
    public void SetUp() {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.get(baseUrl + "/@june0620/feed");
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }

    @Test(enabled = false, description = "글 목록을 불러온다.")
    public void CASE_01_GetPosts() {
        List<WebElement> list = driver.findElements(By.xpath("//div[@id='posts_list']/ul/li"));
        assertTrue(!list.isEmpty(), "글 목록이 있는지 확인");
        for (WebElement post : list) {
            String title = post.findElement(By.xpath("descendant::h2/a")).getText();
            String author = post.findElement(By.xpath("descendant::span[@class='user__name']")).getText();
            System.out.println(author + "님의 글: " + title);
        }
    }

    @Test(timeOut = 60000, description = "로그인 한다.")
    public void CASE_02_Login() throws InterruptedException {
        // Click the login button
        driver.findElement(By.linkText("로그인")).click();
        // type id
        driver.findElement(By.name("username")).sendKeys("june0620");
        // type pw and submit
        WebElement pw = driver.findElement(By.name("password"));
        assertNotNull(pw, "비밀번호 태그가 노출되는지 확인");
        pw.sendKeys(Password.getPw());
        pw.submit();
        Thread.sleep(5000);
    }

    @Test(description = "스팀잇에 글 쓰기 한다. ")
    public void CASE_03_Write() throws InterruptedException {
        // Click the write Button
        List<WebElement> writeBtns = driver.findElements(By.xpath("//a[@href='/submit.html']"));
        assertEquals(writeBtns.size(), 1, "글쓰기 버튼이 노출되는지 확인");
        for (WebElement writeBtn : writeBtns) {
            if (writeBtn.isDisplayed()) {
                writeBtn.click();
                Thread.sleep(2000);
                // type Text and Keys
                WebElement editor = driver.findElement(By.xpath("//textarea[@name='body']"));
                String keys = Keys.chord(Keys.LEFT_SHIFT, Keys.ENTER);
                editor.sendKeys("hello!! world", keys, "hello!!! STEEMIT", Keys.ENTER, "안녕, 스팀잇", Keys.ENTER, "你好!似提姆");
                break;
            }
        }
        Thread.sleep(5000);
    }
    @Test(description = "스티미언 검색", dataProvider = "steemians")
    public void CASE_04_Search(String name) {
        driver.get(baseUrl + "/@" + name);
        /*
         * Some actions
         */
    }
    @DataProvider(name = "steemians")
    public Object[][] members() {
    	return new Object[][] {
    		{"annepink"},
    		{"gghite"},
    		{"lucky2015"},
    		{"honoru"},
    		};
    }
    @AfterClass
    public void tearDownClass() {
        driver.quit();
    }
}
```	
##### TestNG 실행 파일 생성
프로젝트 폴더에서 마우스 우클릭 > TestNG > Convert to TestNG 선택 후 팝업창에서 Finish를 클릭해 주면 프로젝트 root 경로에 testng.xml 파일이 생성된 것을 볼 수 있다. 👇
![image.png](https://files.steempeak.com/file/steempeak/june0620/etWAAlQI-image.png)

파일을 열어 하단 Source탭을 클릭하여 익숙한 xml 포맷으로 전환하자. 👇 
![image.png](https://files.steempeak.com/file/steempeak/june0620/fjulJTVs-image.png)

브라우저 설정은 이 파일을 통해서 하면 되겠다. 
1. suite 태그에 병렬테스트에 필요한 속성을 넣어주고 name은 임의로 넣어주면 된다.
    * parallel 속성은 병렬하려는 개체를 설정한다. 우리는 "tests"로 입력한다.
    * thread-count 속성은 스레드 혀용 개수이다. 일단 "5"로 설정한다. 
2. test 태그는 브라우저 개수만큼 필요하다. Chrome, FireFox 두 개만 할 것이므로 test 태그 두개를 복사한다. name 속성은 알기 쉽게 넣어주면 된다. 
3. test 태그안의 parameter라는 태그는 병렬테스트 시 필수 요소다. name은 browser로 설정하고, value는 각각 chrome, firefox를 넣도록 한다. 메인코드에서 이 값으로 브라우저 를 분기처리 한다. 
4. class 태그에는 실행하려는 package명과 class명을 넣어주면 되고 둘 사이에는 .으로 이어준다. 

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="SteemitAutoTest" parallel="tests" thread-count="5">
	<test name="chrome">
		<parameter name="browser" value="chrome" />
		<classes>
			<class name="com.steem.webatuo.Steemit" />
		</classes>
	</test> <!-- Test -->
	<test name="FireFox">
		<parameter name="browser" value="firefox" />
		<classes>
			<class name="com.steem.webatuo.Steemit" />
		</classes>
	</test> <!-- Test -->
</suite> <!-- Suite -->
```
##### parameter 받기
위에서 설정한 값을 testNg는 `@Parameters`라는 annotation으로 받아올 수 있다. 
`@BeforeClass` 메서드 위에 `@Parameters` 를 추가하고 `testNg.Parameters`를 import한다. 인자는 xml 파일에서 설정한 parameter태그의 name 속성값`browser`를 변수화하여 입력하면 되는데 이는 그 value값을 `@BeforeClass`의 setUp()메서드의 인자로 뿌려주겠다는 뜻이다. 그러므로 setUp() 메서드에도 파라메터를 넣어줘야 한다.
또한 setUp()안 driver도 chrome, firefox 모두 설정을 한 후에 if문으로 분기처리 한다. `@Test` 코드는 수정할 필요 없다.

<sub>두 브라우저가 같이 실행되는 것을 육안으로 확인하기 위해 브라우저 창 최대 크기 설정`driver.manage().window().maximize();`은 제거한다. </sub>
```
    @Parameters({"browser"})
    @BeforeClass
    public void SetUp(String browserName) {
        
        if(browserName.equals("chrome")) {
        	WebDriverManager.chromedriver().setup();
        	driver = new ChromeDriver();	
        }
        else {
        	WebDriverManager.firefoxdriver().setup();
        	driver = new FirefoxDriver();
        }
        	
        driver.get(baseUrl + "/@june0620/feed");
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }
```

##### 영상: 
https://youtu.be/E3XiELWQCLg

.
.
.
.
[Cookie 😅]
Seleniun java lib version: 3.141.59 
java version: 13.0.1
👍 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,