There is a class that I want to test, but when I use mock , I don’t get a normal replacement, that is, the resulting method in the getWinner() class does not return the expected value. When I use a real object, everything works. What am I not using mock correctly?

The class itself:

 public class TicTacToe implements TicTacToeStart { // хранит партии которые можно будет сыграть в процессе игры private ArrayList<Play> games = new ArrayList<>(); // хранит объекты игроков которые победили private ArrayList<Subject> winners = new ArrayList<>(); //имя единственного победителя набравшего 5 побед private String winner; // for test void setGames(ArrayList games) { this.games = games; } // инициализирует объеты партий public void createGames() { for (int i = 0; i < 100; i++) { this.games.add( new Game()); } } // возвращает имя победителя @Override public String getWinner() { return this.winner; } // зацикливает игры до 5 побед @Override public void start() { int count = 0; while (checkWinner().equals("") && count < games.size()) { Play game = this.games.get(count); game.choiceSide(); game.loopMove(); Subject winner = game.initWinner(); if (!winner.getName().equals("nobody")) { this.winners.add(winner); } count++; } this.winner = checkWinner(); } // проверяет кто победил 5 раз и возвращает имя победителя private String checkWinner() { int user = 0, bot = 0; for (Subject winner : winners) { if ("user".equals(winner.getName())) { user++; if (user == 5) return "user"; } if ("bot".equals(winner.getName())) { bot++; if (bot == 5) return "bot"; } } return ""; } } 

Test:

  @Test public void whenThen() { // подготовка StubInput input = new StubInput(); input.setAnswersStr(new String[] { "I", "y", "I", "y", "I", "y", "I", "y", "I", "y"}); input.setAnswersNum(new int[] { 1, 0, 2, 0, 1, 1, 2, 2, 1, 0, 2, 0, 1, 1, 2, 2, 1, 0, 2, 0, 1, 1, 2, 2, 1, 0, 2, 0, 1, 1, 2, 2, 1, 0, 2, 0, 1, 1, 2, 2}); Dialog dialog = new Dialog(); dialog.setInput(input); Game game = new Game(); game.setDialogs(dialog); ArrayList<Play> games = new ArrayList<>(); for (int i = 0; i < 100; i++) { games.add(game); } TicTacToe ticTac = new TicTacToe(); TicTacToe spy = spy(ticTac); spy.setGames(games); spy.start(); // действие String result = spy.getWinner(); // проверка что метод вызвался и что вернул что надо но // я хочу как то проверить это-же только без строчки // spy.setGames(games); и этого огромного стаба verify(spy).getWinner(); assertEquals(result, "bot"); } 
  • one
    Mocks are needed to replace dependencies, and not to work with the class directly tested. Most likely, the mokito simply replaces all the methods in the moke with null-returning stubs, so that the mock in the test does not inadvertently cause side effects. You absolutely exactly, absolutely do not need to mock your class here. - etki
  • 2
    Please describe in words what exactly you are testing. do not forget that a unit test should test only a small (isolated) part of the functionality. A good unit of dough consists of 3 parts: preparation, action and testing. highlight these parts in your test. - Mikhail Vaysman
  • one
    @MikhailVaysman (and cleaning (teardown)) - etki
  • one
    @Etki in the unit test is usually not there, or it is done at the test case level. - Mikhail Vaysman
  • one
    @MikhailVaysman is the xunit-standard - setup, exercise, verify, teardown. - etki

1 answer 1

In my feeling you are mocking the wrong thing.

First, what is the point of this check?

 String result = spy.getWinner(); verify(spy).getWinner(); 

It makes no sense.

Secondly, if you want to check the returned result, then the Game object needs to be mocked up, which would be something like this:

 Game game = mock(Game.class); when(game.initWinner()).thenReturn(/*объект Subject с именем bot*/); ArrayList<Play> games = new ArrayList<>(); for (int i = 0; i < 100; i++) { games.add(game); } //запускаем игру TicTacToe ticTac = new TicTacToe(); ticTac.setGames(games); ticTac.start(); //проверяем результат String result = spy.getWinner(); //сюда ещё можно добавить проверку вызовов метода на объекте game assertEquals(result, "bot"); 

Well, then you can test the Game object with a separate test, in particular its initWinner() method that it returns the desired Subject