1. 소개

이 기사에서는 JAVA API를 사용하여 프로그래밍 방식으로 HTML 사이트 를 배치, 상호 작용 및 테스트 할 수있는 도구 인 HtmlUnit을 소개 합니다.

2. HtmlUnit 정보

HtmlUnit 은 GUI가없는 브라우저로, 사용자가 직접 사용하지 않고 프로그래밍 방식으로 사용하기위한 브라우저입니다.

브라우저는 JavaScript ( Mozilla Rhino 엔진을 통해)를 지원 하며 복잡한 AJAX 기능이있는 웹 사이트에서도 사용할 수 있습니다. 이 모든 것은 Chrome 또는 Firefox와 같은 일반적인 GUI 기반 브라우저를 시뮬레이션하여 수행 할 수 있습니다.

HtmlUnit이라는 이름은 테스트 프레임 워크라고 생각하게 만들 수 있지만 확실히 테스트에 사용할 수 있지만 그 이상을 수행 할 수 있습니다.

또한 Spring 4통합되었으며 Spring MVC 테스트 프레임 워크와 함께 원활하게 사용할 수 있습니다.

3. 다운로드 및 Maven 의존성

HtmlUnit은 SourceForge 또는 공식 웹 사이트 에서 다운로드 할 수 있습니다 . 또한 여기에서 볼 수 있듯이 빌드 도구 (예 : Maven 또는 Gradle)에 포함 할 수 있습니다 . 예를 들어 다음은 현재 프로젝트에 포함 할 수있는 Maven 의존성입니다.

<dependency>
    <groupId>net.sourceforge.htmlunit</groupId>
    <artifactId>htmlunit</artifactId>
    <version>2.23</version>
</dependency>

최신 버전은 여기 에서 찾을 수 있습니다 .

4. 웹 테스트

웹 애플리케이션을 테스트 할 수있는 방법은 여러 가지가 있습니다. 대부분은 여기에서 사이트에서 다뤘습니다.

HtmlUnit을 사용하면 사이트의 HTML을 직접 구문 분석하고, 일반 사용자가 브라우저에서하는 것처럼 상호 작용하고, JavaScript 및 CSS 구문을 확인하고, 양식을 제출하고, 응답을 구문 분석하여 HTML 요소의 내용을 볼 수 있습니다. 모든 것이 순수 자바 코드를 사용합니다.

간단한 테스트 시작해 보겠습니다 . WebClient를 만들고 www.baeldung.com 탐색의 첫 페이지를 가져 옵니다 .

private WebClient webClient;

@Before
public void init() throws Exception {
    webClient = new WebClient();
}

@After
public void close() throws Exception {
    webClient.close();
}

@Test
public void givenAClient_whenEnteringBaeldung_thenPageTitleIsOk()
  throws Exception {
    HtmlPage page = webClient.getPage("/");
    
    Assert.assertEquals(
      "Baeldung | Java, Spring and Web Development tutorials",
        page.getTitleText());
}

웹 사이트에 JavaScript 또는 CSS 문제가있는 경우 해당 테스트를 실행할 때 몇 가지 경고 또는 오류를 볼 수 있습니다. 수정해야합니다.

때로는 수행중인 작업을 알고있는 경우 (예를 들어 수정해서는 안되는 타사 JavaScript 라이브러리에서 발생한 유일한 오류 인 경우) 이러한 오류로 인해 테스트가 실패하지 않도록 방지 할 수 있습니다. setThrowExceptionOnScriptError거짓 :

@Test
public void givenAClient_whenEnteringBaeldung_thenPageTitleIsCorrect()
  throws Exception {
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    HtmlPage page = webClient.getPage("/");
    
    Assert.assertEquals(
      "Baeldung | Java, Spring and Web Development tutorials",
        page.getTitleText());
}

5. 웹 스크랩 핑

자신의 웹 사이트에만 HtmlUnit을 사용할 필요는 없습니다. 결국 브라우저입니다. 원하는 웹을 탐색하고 필요에 따라 데이터를 보내고 검색하는 데 사용할 수 있습니다.

웹 사이트에서 데이터를 가져오고, 구문 분석하고, 저장하고, 분석하는 것은 웹 스크래핑으로 알려진 프로세스이며 HtmlUnit은 가져 오기 및 구문 분석 부분을 도울 수 있습니다.

이전 예제는 웹 사이트에 들어가서 탐색하여 원하는 모든 정보를 검색하는 방법을 보여줍니다.

예를 들어 Baeldung의 전체 기사 아카이브로 이동하여 최신 기사로 이동하여 제목 (첫 번째 <h1> 태그) 을 검색해 보겠습니다 . 우리의 테스트에는 충분할 것입니다. 그러나 더 많은 정보를 저장하려면 예를 들어 제목 (모든 <h2> 태그)도 검색 하여 기사 내용에 대한 기본 아이디어를 얻을 수 있습니다.

ID로 요소를 가져 오는 것은 쉽지만 일반적으로 요소를 찾아야하는 경우 XPath 구문사용하는 것이 더 편리 합니다 . HtmlUnit을 사용하면 사용할 수 있습니다.

@Test
public void givenBaeldungArchive_whenRetrievingArticle_thenHasH1() 
  throws Exception {
    webClient.getOptions().setCssEnabled(false);
    webClient.getOptions().setJavaScriptEnabled(false);

    String url = "/full_archive";
    HtmlPage page = webClient.getPage(url);
    String xpath = "(//ul[@class='car-monthlisting']/li)[1]/a";
    HtmlAnchor latestPostLink 
      = (HtmlAnchor) page.getByXPath(xpath).get(0);
    HtmlPage postPage = latestPostLink.click();

    List<HtmlHeading1> h1  
      = (List<HtmlHeading1>) postPage.getByXPath("//h1");
 
    Assert.assertTrue(h1.size() > 0);
}

먼저 주목하세요.이 경우 우리는 CSS 나 JavaScript에 관심이없고 HTML 레이아웃을 구문 분석하기를 원하므로 CSS와 JavaScript를 해제했습니다.

실제 웹 스크래핑에서 예를 들어 h1h2 제목을 사용할 수 있으며 결과는 다음과 같습니다.

Java Web Weekly, Issue 135
1. Spring and Java
2. Technical and Musings
3. Comics
4. Pick of the Week

검색된 정보가 실제로 Baeldung의 최신 기사와 일치하는지 확인할 수 있습니다.

6. AJAX는 어떻습니까?

HtmlUnit은 일반적으로 AJAX 호출이 완료되기 전에 페이지를 검색하기 때문에 AJAX 기능이 문제가 될 수 있습니다. 웹 사이트를 제대로 테스트하거나 원하는 데이터를 검색하려면 완료해야하는 경우가 많습니다. 이를 처리하는 몇 가지 방법이 있습니다.

  • webClient.setAjaxController (new NicelyResynchronizingAjaxController ()) 사용할 수 있습니다 . 이렇게하면 메인 스레드에서 수행 된 호출이 재 동기화되고 이러한 호출은 테스트 할 안정적인 상태가 있는지 확인하기 위해 동 기적으로 수행됩니다.
  • 웹 애플리케이션의 페이지에 들어갈 때 AJAX 호출이 완료 될 수 있도록 충분한 시간을 갖도록 몇 초 동안 기다릴 수 있습니다. 이를 위해 webClient.waitForBackgroundJavaScript (MILLIS) 또는 webClient.waitForBackgroundJavaScriptStartingBefore (MILLIS)를 사용할 수 있습니다 . 페이지를 검색 한 후 작업하기 전에 호출해야합니다.
  • AJAX 호출 실행과 관련된 예상 조건이 충족 될 때까지 기다릴 수 있습니다. 예를 들면 :
for (int i = 0; i < 20; i++) {
    if (condition_to_happen_after_js_execution) {
        break;
    }
    synchronized (page) {
        page.wait(500);
    }
}
  • 기본적으로 가장 잘 지원되는 웹 브라우저 를 사용하는 새 WebClient () 를 만드는 대신 JavaScript 또는 AJAX 호출에서 더 잘 작동 할 수 있으므로 다른 브라우저를 사용해보십시오. 예를 들어 이것은 Chrome 브라우저를 사용하는 webClient를 생성합니다.
WebClient webClient = new WebClient(BrowserVersion.CHROME);

7. 스프링의 예

자체 Spring 애플리케이션을 테스트하는 경우 작업이 조금 더 쉬워집니다 . 더 이상 실행중인 서버가 필요하지 않습니다 .

매우 간단한 예제 앱을 구현해 보겠습니다. 텍스트를 수신하는 메서드가있는 컨트롤러와 양식이있는 단일 HTML 페이지입니다. 사용자가 양식에 텍스트를 입력하고 양식을 제출하면 해당 양식 아래에 텍스트가 표시됩니다.

이 경우 해당 HTML 페이지에 대해 Thymeleaf 템플릿을 사용합니다 ( 여기 에서 전체 Thymeleaf 예제를 볼 수 있습니다 ).

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { TestConfig.class })
public class HtmlUnitAndSpringTest {

    @Autowired
    private WebApplicationContext wac;

    private WebClient webClient;

    @Before
    public void setup() {
        webClient = MockMvcWebClientBuilder
          .webAppContextSetup(wac).build();
    }

    @Test
    public void givenAMessage_whenSent_thenItShows() throws Exception {
        String text = "Hello world!";
        HtmlPage page;

        String url = "http://localhost/message/showForm";
        page = webClient.getPage(url);
            
        HtmlTextInput messageText = page.getHtmlElementById("message");
        messageText.setValueAttribute(text);

        HtmlForm form = page.getForms().get(0);
        HtmlSubmitInput submit = form.getOneHtmlElementByAttribute(
          "input", "type", "submit");
        HtmlPage newPage = submit.click();

        String receivedText = newPage.getHtmlElementById("received")
            .getTextContent();

        Assert.assertEquals(receivedText, text);     
    }
}

여기서 핵심 WebApplicationContext 에서 MockMvcWebClientBuilder사용하여 WebClient 객체를 빌드 하는 것 입니다. WebClient를 사용하면 탐색의 첫 번째 페이지 ( localhost 에서 제공하는 방법에 주목)를 가져 와서 거기에서 탐색을 시작할 수 있습니다.

보시다시피 테스트는 양식을 구문 분석하여 메시지를 입력하고 (ID가 "message"인 필드에) 양식을 제출하고 새 페이지에서 수신 된 텍스트 (ID가 "수신"인 필드)가 제출 한 텍스트와 동일합니다.

8. 결론

HtmlUnit은 마치 브라우저에서 웹을 사용하는 것처럼 웹 애플리케이션을 쉽게 테스트하고 양식 필드를 채우고 제출할 수있는 훌륭한 도구입니다.

Spring 4와 원활하게 통합되며 Spring MVC Test 프레임 워크와 함께 웹 서버 없이도 모든 페이지의 통합 테스트를 수행 할 수있는 매우 강력한 환경을 제공합니다.

또한 HtmlUnit을 사용하면 데이터 가져 오기, 구문 분석, 저장 및 분석 (웹 스크래핑)과 같은 웹 탐색과 관련된 모든 작업을 자동화 할 수 있습니다.

Github 에서 코드 얻을 수 있습니다 .