Простота кода

Простота кода

есть лютая благодать
08.07.19

Давайте поговорим о простоте кода. Наверное, все согласны с тем, что простой код - хороший код. Только все понимают “простоту” по-разному.

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

Задача

Есть некий список типа “Gmail” с чекбоксами и заголовками. Требуется пэджобжект, который позволил бы найти по заголовку и кликнуть один или несколько чекбоксов.

Структура HTML

не важна, но схематично выглядит она так:

<div class="box">
  <div class="boxCheckbox">
    <input type="checkbox">...</input>  
  </div>
  <div class="boxLabel">
    Here is checkbox #1  
  </div>
</div>
<div class="box">
  ...
</div>
...

т.е. у нас есть несколько <div class="box">, внутри каждого пара <div class="boxCheckbox"> + <div class="boxLabel">.

Сложный код

Перед вами типичный код, который мне приходилось видеть примерно миллион раз.

Это олицетворение современной автоматизации тестирования (так мне иногда кажется).

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import java.util.ArrayList;
import java.util.List;

public class SeleniumPageObject {

  // Search for element index in the list by title
  public static List<Integer> findListIndexesByTitle(List<WebElement> elementList, String SearchText) {
    List<Integer> ints = new ArrayList<>();
    for (int i = 0; i < elementList.size(); i++) {
      if (elementList.get(i).getText().contains(SearchText)) {
        ints.add(i);
      }
    }
    return ints;
  }

  // Buttons in the boxes
  @FindBy(xpath = "//div[@class='boxCheckbox']")
  private List<WebElement> selectCheckBoxesInBoxes;

  // Titles for boxes
  @FindBy(xpath = "//div[@class='boxLabel']")
  private List<WebElement> listOfTitlesInBoxes;

  // Select Box by title
  public void selectBoxByTitle(String searchTitle) {
    int index = findListIndexesByTitle(listOfTitlesInBoxes, searchTitle).get(0);
    selectBoxByIndex(index);
  }

  // Select Box by index
  private void selectBoxByIndex(int elPosition) {
    selectCheckBoxesInBoxes.get(elPosition).click();
  }

  // Select All Boxes by title
  public void selectAllBoxesByTitle(String searchTitle) {
    List<Integer> ints = findListIndexesByTitle(listOfTitlesInBoxes, searchTitle);
    for (int i = 0; i < ints.size(); i++) {
      selectBoxByIndex(ints.get(i));
    }
  }
}

Не буду повторяться, почему комментарии в коде не нужны, что @FindBy обычно ничего не упрощает и т.д. Просто сравните эти два куска кода.

Простой код

А вот во что я смог превратить этот код, переписав на Selenide:

import com.codeborne.selenide.SelenideElement;

import static com.codeborne.selenide.Condition.text;
import static com.codeborne.selenide.Selenide.$$;

public class SelenidePageObject {
  public void selectBoxByTitle(String title) {
    selectBox($$(".boxLabel").findBy(text(title)));
  }

  public void selectAllBoxesByTitle(String searchTitle) {
    $$(".boxLabel").filterBy(text(searchTitle)).forEach(this::selectBox);
  }

  private void selectBox(SelenideElement boxLabel) {
    boxLabel.closest(".box").find(".boxCheckbox").click();
  }
}

Правда, ПРОСТО?

Этот вариант тоже не идеален. Но главное - он гораздо короче и проще. Его проще поддерживать. Его проще понять. Его проще поменять. Его проще переписать с нуля, в конце концов.

P.S. Заметили трюк? Я сказал, что переписал код на Селенид, но на самом деле выигрыш получился не столько от Селенида, сколько от упрощения селекторов, выкидывания лишнего, использования лямбд (т.е. более современных средств языка). В общем, вы все с этим справитесь.

Цените простоту, друзья!


Андрей Солнцев

ru.selenide.org

08.07.19