HtmlUnitの紹介

HtmlUnitの概要

1. 前書き

この記事では、interact with and test an HTML site programmatically, using JAVA APIsを簡単に作成できるツールであるHtmlUnitを紹介します。

2. HtmlUnitについて

HtmlUnitは、GUIを使用しないブラウザーであり、ユーザーが直接使用するのではなく、プログラムで使用することを目的としたブラウザーです。

ブラウザは(Mozilla Rhinoエンジンを介して)JavaScriptをサポートし、複雑なAJAX機能を備えたWebサイトでも使用できます。 これらはすべて、ChromeやFirefoxなどの典型的なGUIベースのブラウザーをシミュレートして実行できます。

HtmlUnitという名前は、それがテストフレームワークであると思わせるかもしれませんが、テストには間違いなく使用できますが、それ以上のことができます。

また、integrated into Spring 4であり、SpringMVCテストフレームワークとシームレスに使用できます。

3. ダウンロードとMavenの依存関係

HtmlUnitは、downloaded from SourceForgeまたはofficial websiteから取得できます。 また、hereを確認できるように、ビルドツール(MavenやGradleなど)に含めることもできます。 たとえば、これは現在プロジェクトに含めることができるMavenの依存関係です。


    net.sourceforge.htmlunit
    htmlunit
    2.23

最新バージョンはhereで見つけることができます。

4. Webテスト

Webアプリケーションをテストするには多くの方法があります。そのほとんどは、ここでサイトのどこかで説明しました。

HtmlUnitを使用すると、サイトのHTMLを直接解析し、通常のユーザーがブラウザーから行うのと同じように対話し、JavaScriptとCSS構文を確認し、フォームを送信し、応答を解析してHTML要素のコンテンツを表示できます。 すべて、純粋なJavaコードを使用します。

簡単なテストから始めましょう:WebClientを作成し、www.example.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_whenEnteringexample_thenPageTitleIsOk()
  throws Exception {
    HtmlPage page = webClient.getPage("/");

    Assert.assertEquals(
      "example | Java, Spring and Web Development tutorials",
        page.getTitleText());
}

ウェブサイトにJavaScriptまたはCSSの問題がある場合、そのテストを実行すると、警告またはエラーが表示されます。 それらを修正する必要があります。

場合によっては、何をしているのかがわかっている場合(たとえば、変更してはならないサードパーティのJavaScriptライブラリからのエラーのみが表示されている場合)、%(を呼び出して、これらのエラーによってテストが失敗するのを防ぐことができます。 t0)sとfalse

@Test
public void givenAClient_whenEnteringexample_thenPageTitleIsCorrect()
  throws Exception {
    webClient.getOptions().setThrowExceptionOnScriptError(false);
    HtmlPage page = webClient.getPage("/");

    Assert.assertEquals(
      "example | Java, Spring and Web Development tutorials",
        page.getTitleText());
}

5. Webスクレイピング

自分のWebサイトのためだけにHtmlUnitを使用する必要はありません。 結局のところ、これはブラウザです。これを使用して、好きなWebをナビゲートし、必要に応じてデータを送信および取得できます。

Webサイトからのデータの取得、解析、保存、分析はWebスクレイピングと呼ばれるプロセスであり、HtmlUnitはパーツの取得と解析に役立ちます。

前の例は、任意のWebサイトにアクセスしてそのWebサイトをナビゲートし、必要な情報をすべて取得する方法を示しています。

たとえば、例の記事の完全なアーカイブに移動し、最新の記事に移動して、そのタイトル(最初の<h1>タグ)を取得しましょう。 私たちのテストでは、それで十分です。ただし、より多くの情報を保存したい場合は、たとえば、見出し(すべての<h2>タグ)を取得して、記事の基本的な考え方を把握することもできます。

IDで要素を取得するのは簡単ですが、一般的に、要素を見つける必要がある場合は、use XPath syntaxの方が便利です。 HtmlUnitを使用することで、使用できるようになります。

@Test
public void givenexampleArchive_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 h1
      = (List) postPage.getByXPath("//h1");

    Assert.assertTrue(h1.size() > 0);
}

まず、この場合、CSSやJavaScriptに興味がなく、HTMLレイアウトを解析したいだけなので、CSSとJavaScriptをオフにしました。

実際のWebスクレイピングでは、たとえばh1h2のタイトルを取ることができ、結果は次のようになります。

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

取得した情報が実際に例の最新の記事に対応していることを確認できます。

image

6. AJAXはどうですか?

HtmlUnitは通常、AJAX呼び出しが完了する前にページを取得するため、AJAX機能が問題になる可能性があります。 多くの場合、Webサイトを適切にテストしたり、必要なデータを取得したりするために、それらを完了する必要があります。 それらに対処する方法がいくつかあります。

  • webClient.setAjaxController(new NicelyResynchronizingAjaxController())を使用できます。 これにより、メインスレッドから実行された呼び出しが再同期され、これらの呼び出しは同期して実行され、テストする安定した状態が確保されます。

  • Webアプリケーションのページに入るとき、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);
    }
}
  • デフォルトで最もサポートされているWebブラウザーであるnew WebClient()を作成する代わりに、JavaScriptまたはAJAX呼び出しでより適切に機能する可能性があるため、他のブラウザーを試してください。 たとえば、これはChromeブラウザを使用するwebClientを作成します:

WebClient webClient = new WebClient(BrowserVersion.CHROME);

7. 春の例

独自のSpringアプリケーションをテストしている場合は、少し簡単になります - we no longer need a running server

非常に単純なサンプルアプリを実装しましょう。テキストを受け取るメソッドを備えたコントローラーと、フォームを備えた単一のHTMLページです。 ユーザーはフォームにテキストを入力し、フォームを送信すると、そのフォームの下にテキストが表示されます。

この場合、そのHTMLページにThymeleafテンプレートを使用します(完全なThymeleafの例hereを見ることができます):

@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が「メッセージ」のフィールドに)、フォームを送信し、新しいページで受信したテキスト(IDがフィールドにあるフィールドreceivedâ€)は、送信したテキストと同じです。

8. 結論

HtmlUnitは、Webアプリケーションを簡単にテストし、フォームフィールドに入力して、ブラウザでWebを使用しているかのように送信できる優れたツールです。

Spring 4とシームレスに統合され、Spring MVCテストフレームワークと連携して、Webサーバーがなくてもすべてのページの統合テストを行うための非常に強力な環境を提供します。

また、HtmlUnitを使用すると、データの取得、解析、保存、分析(Webスクレイピング)など、Webブラウジングに関連するタスクを自動化できます。

コードover on Githubを取得できます。