Введение в HtmlUnit

Введение в HtmlUnit

1. Вступление

В этой статье мы познакомим вас с HtmlUnit, инструментом, который позволяет нам, проще говоря,interact with and test an HTML site programmatically, using JAVA APIs.

2. О HtmlUnit

HtmlUnit - это браузер без графического интерфейса пользователя - браузер, предназначенный для использования программными средствами, а не напрямую пользователем.

Браузер поддерживает JavaScript (через движокMozilla Rhino) и может использоваться даже для веб-сайтов со сложными функциями AJAX. Все это можно сделать, имитируя типичный браузер с графическим интерфейсом, такой как Chrome или Firefox.

Название HtmlUnit может наводить на мысль, что это среда тестирования, но, хотя ее определенно можно использовать для тестирования, она может гораздо больше.

Он также былintegrated into Spring 4 и может без проблем использоваться вместе со средой тестирования Spring MVC.

3. Загрузка и зависимость от Maven

HtmlUnit может бытьdownloaded from SourceForge или изofficial website. Кроме того, вы можете включить его в свой инструмент для сборки (например, Maven или Gradle), как вы можете видетьhere. Например, это зависимость Maven, которую вы в настоящее время можете включить в свой проект:


    net.sourceforge.htmlunit
    htmlunit
    2.23

Последнюю версию можно найтиhere.

4. Веб-тестирование

Существует множество способов тестирования веб-приложения, большинство из которых мы рассмотрели здесь на сайте в тот или иной момент.

С 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, которые вам не следует изменять), вы можете предотвратить сбой теста из-за этих ошибок, вызвавsetThrowExceptionOnScriptError с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. Веб-парсинг

Вам не нужно использовать HtmlUnit только для своих сайтов. В конце концов, это браузер: вы можете использовать его для навигации по любой сети, которая вам нравится, отправки и получения данных по мере необходимости.

Извлечение, анализ, хранение и анализ данных с веб-сайтов - это процесс, известный как очистка веб-страниц, а HtmlUnit может помочь вам с извлечением и анализом частей.

В предыдущем примере показано, как мы можем войти на любой веб-сайт и перемещаться по нему, получая всю необходимую нам информацию.

Например, давайте перейдем к полному архиву статей, перейдем к последней статье и получим ее заголовок (первый тег<h1>). Для нашего теста этого будет достаточно; но, если бы мы хотели сохранить больше информации, мы могли бы, например, получить заголовки (все теги<h2>), таким образом имея общее представление о том, о чем статья.

Получить элементы по идентификатору несложно, но, как правило, если вам нужно найти элемент, удобнее использовать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.

В реальном веб-парсинге вы можете взять, например, заголовкиh1 иh2, и результат будет примерно таким:

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

Вы можете проверить, действительно ли полученная информация соответствует последней статье в примере:

image

6. А как насчет AJAX?

Функциональные возможности AJAX могут быть проблемой, поскольку HtmlUnit обычно извлекает страницу до завершения вызовов 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);
    }
}
  • Вместо созданияnew WebClient(), по умолчанию для которого используется наиболее поддерживаемый веб-браузер, попробуйте другие браузеры, поскольку они могут лучше работать с вашими вызовами JavaScript или AJAX. Например, это создаст веб-клиента, который использует браузер Chrome:

WebClient webClient = new WebClient(BrowserVersion.CHROME);

7. Пример с Spring

Если мы тестируем собственное приложение Spring, все станет немного проще -we no longer need a running server.

Давайте реализуем очень простой пример приложения: просто контроллер с методом, получающим текст, и одна HTML-страница с формой. Пользователь может ввести текст в форму, отправить форму, и текст будет показан под этой формой.

В этом случае мы будем использовать шаблонThymeleaf для этой HTML-страницы (вы можете увидеть полный пример Thymeleafhere):

@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);
    }
}

Ключевым моментом здесь является создание объектаWebClient с использованиемMockMvcWebClientBuilder изWebApplicationContext. С помощьюWebClient мы можем получить первую страницу навигации (обратите внимание, как она обслуживаетсяlocalhost) и начать просмотр оттуда.

Как видите, тест разбирает форму, вводит сообщение (в поле с идентификатором «message»), отправляет форму и на новой странице утверждает, что полученный текст (поле с идентификатором «receive») является так же, как текст, который мы представили.

8. Заключение

HtmlUnit - отличный инструмент, который позволяет вам легко тестировать ваши веб-приложения, заполняя поля форм и отправляя их так же, как если бы вы использовали Интернет в браузере.

Он легко интегрируется с Spring 4, и вместе с Spring MVC Test Framework они предоставляют вам очень мощную среду для проведения интеграционных тестов всех ваших страниц даже без веб-сервера.

Кроме того, используя HtmlUnit, вы можете автоматизировать любую задачу, связанную с просмотром веб-страниц, такую ​​как выборка, анализ, хранение и анализ данных (очистка веб-страниц).

Вы можете получить кодover on Github.