Cucumber Java, как обновить элемент в DataTable

Я пытаюсь следовать примеру из учебника Cucumber, но он написан для Ruby, и я пытаюсь написать его на Java. У меня возникли трудности с реализацией шага @When, поскольку он требует от меня обновления DataTable, и я получаю следующее исключение:

java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableList.set(Collections.java:1308)
at cucumber_tutorial.expressive_scenarios.chapter5.features.step_definitions.BoardSteps.player_x_plays_in_row_column(BoardSteps.java:36)
at ✽.When player x plays in row 2, column 1(tic_tac_toe.feature:8)

Моя особенность заключается в следующем,

Feature:
  Scenario:
    Given a board like this:
      |   | 1 | 2 | 3 |
      | 1 |   |   |   |
      | 2 |   |   |   |
      | 3 |   |   |   |
    When player x plays in row 2, column 1
    Then the board should look like this:
      |   | 1 | 2 | 3 |
      | 1 |   |   |   |
      | 2 | x |   |   |
      | 3 |   |   |   |

После запуска функции и получения сгенерированных фрагментов кода у меня есть следующее (я также добавил пару строк),

package cucumber_tutorial.expressive_scenarios.chapter5.features.step_definitions;

import cucumber.api.DataTable;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import java.util.List;

public class BoardSteps {

    List<List<String>> boardList;

    @Given("^a board like this:$")
    public void a_board_like_this(DataTable dataTable) throws Throwable {
        boardList = dataTable.raw();
        System.out.println(boardList);
        // Write code here that turns the phrase above into concrete actions
        // For automatic transformation, change DataTable to one of
        // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
        // E,K,V must be a scalar (String, Integer, Date, enum etc)
        //throw new PendingException();
    }

    @When("^player x plays in row (\\d+), column (\\d+)$")
    public void player_x_plays_in_row_column(int row, int col) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        //board.
        //throw new PendingException()
        boardList.get(row).set(col, "x");
    }

    @Then("^the board should look like this:$")
    public void the_board_should_look_like_this(DataTable expectedTable) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        // For automatic transformation, change DataTable to one of
        // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
        // E,K,V must be a scalar (String, Integer, Date, enum etc)
        expectedTable.diff(boardList);
        //throw new PendingException();
    }

}

Проблема, по-видимому, заключается в том, что dataTable.raw() на шаге @Given присваивает немодифицируемый тип коллекции boardList и, таким образом, делает его недоступным для обновления. Пример Ruby просто имеет,

row, col = row.to_i, col.to_i​   
@board[row][col] = ​'x'​

мое исключение выбрасывается из,

boardList.get(row).set(col, "x"); //this line throws the exception

Может кто-нибудь посоветовать мне стандартный способ обновления DataTable с помощью Java?


person robbie70    schedule 04.02.2019    source источник
comment
Воссоздайте новую таблицу данных в вашем коде, используя значения в существующей таблице данных.   -  person Grasshopper    schedule 05.02.2019
comment
@Grasshopper спасибо - не могли бы вы показать пример того, как это сделать   -  person robbie70    schedule 05.02.2019
comment
Проще всего было бы использовать аргумент List‹List‹String› вместо DataTable в определении шага. Затем вы можете использовать цикл для создания нового списка списка.   -  person Grasshopper    schedule 05.02.2019
comment
@Grasshopper спасибо - ваш совет помог мне решить эту проблему - я опубликую свое решение. Должен признаться, я удивлен, что мне пришлось сделать это таким образом - это кажется немного неэлегантным.   -  person robbie70    schedule 05.02.2019
comment
Вы можете посмотреть исходный код DataTable. Может быть, есть метод, который возвращает модифицируемую структуру, хотя я сомневаюсь. Думаю, логика в том, что тестовые данные должны быть доступны на уровне файла функций, а не скрыты в коде.   -  person Grasshopper    schedule 05.02.2019


Ответы (2)


Как предложил @Grasshopper в комментариях выше, я реализовал функцию преобразования convertDataTableToModifiableList для преобразования неизменяемого DataTable в объект List<List<String>>, который я могу обновить. Мое рабочее решение теперь, как показано,

import cucumber.api.DataTable;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

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

public class BoardSteps {

    List<List<String>> boardList;

    @Given("^a board like this:$")
    public void a_board_like_this(DataTable dataTable) throws Throwable {
        boardList = convertDataTableToModifiableList(dataTable);
        System.out.println(boardList);
        // Write code here that turns the phrase above into concrete actions
        // For automatic transformation, change DataTable to one of
        // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
        // E,K,V must be a scalar (String, Integer, Date, enum etc)
        //throw new PendingException();
    }

    @When("^player x plays in row (\\d+), column (\\d+)$")
    public void player_x_plays_in_row_column(int row, int col) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        //board.
        //throw new PendingException()
        boardList.get(row).set(col, "x");
    }

    @Then("^the board should look like this:$")
    public void the_board_should_look_like_this(DataTable expectedTable) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        // For automatic transformation, change DataTable to one of
        // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
        // E,K,V must be a scalar (String, Integer, Date, enum etc)
        expectedTable.diff(boardList);
        //throw new PendingException();
    }

    private List<List<String>> convertDataTableToModifiableList(DataTable dataTable){
        List<List<String>> lists = dataTable.asLists(String.class);
        List<List<String>> updateableLists = new ArrayList<>();
        for (int i = 0; i < lists.size(); i++){
            List<String> list = lists.get(i);
            List<String> updateableList = new ArrayList<>();
            for (int j = 0; j < list.size(); j++){
                updateableList.add(j, list.get(j));
            }
            updateableLists.add(i, updateableList);
        }
        return updateableLists;
    }

}

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

person robbie70    schedule 05.02.2019

Это решение, которое я придумал.

public class BoardSteps {

    private ArrayList<List<String>> board;

    @Given("a board like this:")
    public void aBoardLikeThis(DataTable board) {
        this.board = new ArrayList<List<String>>();
        for (List<String> row: board.asLists()) {
            this.board.add(new ArrayList<String>(row));
        }

    }

    @When("player x plays in row {int}, column {int}")
    public void playerXPlaysInRowColumn(Integer row, Integer column) {
        this.board.get(row).set(column, "x");

    }

    @Then("the board should look like this:")
    public void theBoardShouldLookLikeThis(DataTable expectedBoard) {
        expectedBoard.diff(DataTable.create(board));
    }

}
person Geoff Hayward    schedule 10.12.2019
comment
не уверен, так как я не знаком с этим контентом, но должен ли playerXPlaysInRawColumn на самом деле быть playerXPlaysInRowColumn? (ряд против необработанных) - person Alex Hague; 11.12.2019
comment
Хорошо заметил @AlexHague. Это была опечатка. - person Geoff Hayward; 12.12.2019