Как запустить модульные тесты в Jupiter для класса, не вызывая другие методы для изменения объекта?

#java #unit-testing #junit #junit-jupiter

Вопрос:

Я пытаюсь создать класс крестиков-ноликов и провести модульное тестирование всех методов. Прямо сейчас мой файл класса выглядит следующим образом:

 public class TicTacToe {  public static final Character PLAYER_1 = 'X';  public static final Character PLAYER_2 = 'O';  public static final Integer BOARD_SIZE = 3;   private char[][] board;  private char currentPlayer;   public TicTacToe() {  board = new char[BOARD_SIZE][BOARD_SIZE];  initializeBoard();  currentPlayer = PLAYER_1;  }   public void initializeBoard() {  for(char[] row: board) {  Arrays.fill(row, '-');  }  }   public void printBoard() {  for(int i = 0; i lt; BOARD_SIZE; i  ) {  for(int j = 0; j lt; BOARD_SIZE; j  ) {  System.out.print(board[i][j]);  if(j == BOARD_SIZE - 1) {  System.out.println();  }  else {  System.out.print(" ,");  }  }  }  }   public boolean makeMove(int x, int y) {  if(x gt;= BOARD_SIZE || y gt;= BOARD_SIZE || x lt; 0 || y lt; 0 || board[x][y] != '-') {  return false;  }  board[x][y] = currentPlayer;  currentPlayer = currentPlayer == PLAYER_1 ? PLAYER_2 : PLAYER_1;  return true;  } // more methods are below }  

Если бы я хотел проверить, что printBoard() работает, когда вся доска заполнена, как бы я это сделал, не вызывая makeMove() или не делая все мои переменные класса общедоступными?

В настоящее время мой файл тестирования выглядит следующим образом:

 import org.junit.*; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test;  import java.io.*;  import static org.junit.jupiter.api.Assertions.*;  class TicTacToeTest {  private final PrintStream standardOut = System.out;  private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();   @BeforeEach  public void setUp() {  System.setOut(new PrintStream(outputStreamCaptor));  }   @org.junit.jupiter.api.Test   @AfterEach  public void tearDown() {  System.setOut(standardOut);  }   @Test  void initializeBoard() {  }   @Test  void printBoard() {  TicTacToe game = new TicTacToe();  game.printBoard();   assertEquals("- ,- ,-rn- ,- ,-rn- ,- ,-", outputStreamCaptor.toString()  .trim());   // I want to test that a full board works for printBoard() right here.   } // more testing methods below }  

Я видел что-то об использовании @Jailbreak в Manifold, но я не мог заставить это работать. Если это кому-то поможет, я использую IntelliJ. Спасибо вам за любую помощь, которую вы окажете!

Ответ №1:

Три дополнительных варианта (есть и другие):

  1. Создайте второй конструктор TicTacToe, где вы можете перейти на предварительно заполненную доску public TicTacToe(char[][] board)
  2. Добавьте дополнительный метод public void loadBoard(char[][] board) .
  3. Используйте отражение для заполнения переменной платы. (плохой вариант, потому что это может привести к другому состоянию)
  4. Добавьте конструктор, закрытый для пакета, и пусть оба класса находятся в одном пакете.
  5. Создайте метод набора данных с закрытым пакетом и получите доступ к нему в части упорядочения вашего кода.

Вы также можете сделать что-то с частичным издевательством, но я думаю, что это также не лучший вариант в данной ситуации.

Еще один хороший вариант — создать отдельный класс для распечатки платы:

 public class BoardPrinter {    public BoardPrinter() {}   public printBoard(char[][] board} {  // print the board  } }