Нужна помощь в написании теста для консольных крестиков-ноликов

524
04 января 2017, 02:01

У меня консольная программа крестики-нолики. Для тестирования ввода с консоли я использую класс StubInput:

public class StubInput implements In {
    /**
     * Contain answers required string type.
     */
    private String[] answersStr;
    /**
     * Counter for get next value from answersStr.
     */
    private int countStr = 0;
    /**
     * Contain answers required int type.
     */
    private int[] answersNum;
    /**
     * Counter for get next value from answersNum.
     */
    private int countNum = 0;
    public void setAnswersStr(String[] answersStr) {
        this.answersStr = answersStr;
    }
    public void setAnswersNum(int[] answersNum) {
        this.answersNum = answersNum;
    }
    /**
     * Emulator string input stream.
     * @return string answer.
     */
    @Override
    public String getStrInput() {
        return this.answersStr[this.countStr++];
    }
    /**
     * Emulator int input stream.
     * @return int answer.
     */
    @Override
    public int getNumInput() {
        return this.answersNum[this.countNum++];
    }
}

И для класса отвечающего за доску в котором есть возможность выбора размера доски это сработало:

public class Desc implements Board {
    /**
     * Information about statement desc for bot.
     */
    private static char[][] infoDesc;

    /**
     * Input for get console in.
     */
    private In input = new Input();
    /**
     * Desc for game.
     */
    private char[][] desc = new char[3][3];
    /**
     * Pointer on desc. It's information for bot about statement desc.
     *
     * @return current statement desc.
     */
    public static char[][] getInfoDesc() {
        return infoDesc;
    }
    /**
     * Use for test class StubInput.
     *
     * @param input emulation console input stream.
     */
    @Override
    public void setInput(In input) {
        this.input = input;
    }
    /**
     * Getter for desc. Init infoDesc.
     *
     * @return desc.
     */
    @Override
    public char[][] getDesc() {
        infoDesc = this.desc;
        return this.desc;
    }
    /**
     * For choice desc size.
     */
    @Override
    public void initDescSize() {
        System.out.println("Хотите использовать стандартный размер поля: y/n");
        String answer = this.input.getStrInput();
        if (answer.equals("y")) {
            System.out.println("Установлен стандартный размер поля: 3/3");
        } else if (answer.equals("n")) {
            this.initNonstandardDesc();
        }
        this.initContentDesc();
    }
    /**
     * Install desc nonstandard size.
     */
    private void initNonstandardDesc() {
        System.out.println("Введите размер сторон:");
        int i = this.input.getNumInput();
        this.desc = new char[i][i];
        System.out.println(format("Установлен размер поля: %s/%s", i, i));
    }
    /**
     * Fill desc empty call. Empty is ' '.
     */
    private void initContentDesc() {
        for (int i = 0; i != this.desc.length; i++) {
            for (int j = 0; j != this.desc.length; j++) {
                this.desc[j][i] = ' ';
            }
        }
    }
}

Вот тест к нему:

public class DescTest {
    /**
     * Test choice standard desc size.
     * @see Desc#initDescSize()
     */
    @Test
    public void whenUserChoiceStandardDescSizeThenDeskSizeEqualTreeToTree() {
        StubInput input = new StubInput();
        Board desc = new Desc();
        input.setAnswersStr(new String[]{"y"});
        desc.setInput(input);
        desc.initDescSize();
        int result = desc.getDesc().length;
        assertThat(result, is(3));
    }
    /**
     * Test case when user choice nonstandard desc size.
     */
    @Test
    public void whenUserChoiceNonstandardThenSizeThenDeskSizeEqualUserInput() {
        StubInput input = new StubInput();
        Board desc = new Desc();
        input.setAnswersStr(new String[]{"n"});
        input.setAnswersNum(new int[]{5});
        desc.setInput(input);
        desc.initDescSize();
        int result = desc.getDesc().length;
        assertThat(result, is(5));
    }
}

Однако когда я попробовал протестировать класс самой игры у меня ничего не вышло. Вот сама игра:

public class Game implements Round {
    /**
     * Desc for play.
     */
    private Board desc = new Desc();
    /**
     * winner.
     */
    private Gamers winner;
    /**
     * For input.
     */
    private In input = new Input();
    /**
     * List contain all gamer: bot and user.
     */
    private ArrayList<Gamers> gamers = new ArrayList<>();
    /**
     * Util class contain algorithm determining winner.
     */
    private Validation valid = new ValidationWinnerUtil();
    @Override
    public Gamers getWinner() {
        return this.winner;
    }
    /**
     * Check correct move.
     * @param player player which move.
     * @return true if move success. False if move fail
     */
    private boolean move(Gamers player) {
        player.setPosit();
        if (this.desc.getDesc()[player.getPosit().getY()][player.getPosit().getX()] == ' ') {
            this.desc.getDesc()[player.getPosit().getY()][player.getPosit().getX()] = player.getColor();
            return true;
        } else {
            System.err.println("Так ходить нельзя!");
            return false;
        }
    }
    /**
     * Determines fist move.
     */
    @Override
    public void firstMove() {
        this.desc.initDescSize();
        System.out.println("Кто ходит первым? Enter: Bot / I");
        if (this.input.getStrInput().toUpperCase().equals("BOT")) {
            this.fstMoveBot();
        } else {
            this.fstMoveUsr();
        }
        Printer.printDesc(this.desc.getDesc());
        this.loopMoves();
    }
    /**
     * Configurable statement game if bot move first.
     */
    private void fstMoveBot() {
        this.gamers.add(new Bot(Colors.X.getColor()));
        this.gamers.add(new User(Colors.O.getColor()));
    }
    /**
     * Configurable statement game if user choice move first.
     */
    private void fstMoveUsr() {
        this.gamers.add(new User(Colors.X.getColor()));
        this.gamers.add(new Bot(Colors.O.getColor()));
    }
    /**
     * Loop game process.
     */
    private void loopMoves() {
        Gamers winner = null;
        while (this.valid.gameCanGoOn(this.desc.getDesc())) {
            for (Gamers gamer : this.gamers) {
                if (this.valid.gameCanGoOn(this.desc.getDesc()) &&
                        this.move(gamer)
                        ) {
                    Printer.printDesc(this.desc.getDesc());
                    winner = gamer;
                } else if (this.valid.gameCanGoOn(this.desc.getDesc())) {
                    this.mistakeMove(gamer);
                    Printer.printDesc(this.desc.getDesc());
                }
            }
        }
        this.initResultGame(winner);
    }
    /**
     * Give more chance when player which mistake - try move in busy cell.
     * @param gamer player which mistake.
     */
    private void mistakeMove(Gamers gamer) {
        while (!this.move(gamer)) {
            mistakeMove(gamer);
        }
    }
    /**
     * Init result game.
     * @see TickTack#winners
     * @param winner gamer for estimated award.
     */
    private void initResultGame(Gamers winner) {
        if (!this.valid.emptyCellExist(  this.desc.getDesc()) &&
                !this.valid.winnerDetermines(this.desc.getDesc())
                ) {
            System.out.println("Ничья.");
        } else if (this.valid.winnerDetermines(  this.desc.getDesc())) {
            this.winner = winner;
            System.out.println(format("Победитель: %s", winner.getColor()));
        }
    }
}

Проблема заключается в том что когда метод firstMove() начинает работу то поток выполнения передается до самого конца партии, и у меня нет возможности для того чтобы подменить Input на StubInput в объекте пользователя вот тут:

private void fstMoveBot() {
        this.gamers.add(new Bot(Colors.X.getColor()));
        this.gamers.add(new User(Colors.O.getColor())); // вот тут new User
    }

Но и перед запуском firstMove() я тоже этой подмены сделать не могу так как firstMove() все равно их перепишет.

В общем такая проблема... С заранее не записать так как все равно перепишется, а в процессе вклинится не как. И даже если я и создам указатель на:

this.gamers.add(какой-то_указатель_с_полей = new User(Colors.O.getColor()))

это так же ничего не даст.

Помогите пожалуйста. Что мне делать? Как мне протестировать это? Может сам код г-но, потому и не тестируется тогда подскажите в чем. В общем вот. Буду безумно благодарен за помощь и любую конструктивную критику...

READ ALSO
Помогите сократить программу. java

Помогите сократить программу. java

Есть задание сделать анаграмму ,например lashjkuj2 akcc66Чтобы все не буквенные символы остались на месте? Я сделал так

542
Как найти самую длинную строку в List?

Как найти самую длинную строку в List?

Подскажите, пожалуйста, способ нахождения самой длинной строки в ArrayList

774
roll back error

roll back error

Запустил приложение все работало ,обнавил страницу выдал ошибку перезапустил снов одно и тожеЧто это с чем связано ребята??помогите при...

570
В чём различие между jdk, sdk и j2sdk?

В чём различие между jdk, sdk и j2sdk?

В чём заключается различие между JDK, SDK и J2SDK?

587