AssertNotNull AssertionFailedError: ожидается: не <null>

Я тестирую приложение, в котором создается метод и объект, и я пытаюсь проверить, действительно ли объект создается следующим образом:

   @Test
public void testCreateWagerGetsCreated(){
    DefaultSportsBettingService service = mock(DefaultSportsBettingService.class);
    Player player = mock(Player.class);
    Outcome outcome = new Outcome(null,"description",BigDecimal.valueOf(2),false);
    BigDecimal bd = BigDecimal.valueOf(100);
    assertNotNull(service.createWager(player,outcome, bd));
}

Однако тест не выдает эту ошибку:

org.opentest4j.AssertionFailedError: expected: not <null>

    at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
    at org.junit.jupiter.api.Assertions.fail(Assertions.java:134)
    at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
    at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
    at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:31)
    at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:300)
    at com.epam.training.sportsbetting.Tester.testCreateWagerGetsCreated(Tester.java:64)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

Я пытался издеваться над классами домена и создавать их экземпляры, оба выдают одну и ту же ошибку. Что я делаю не так?

Класс игрока:

public class Player extends User{

private String name;

private BigDecimal balance;

private Currency currency;

public Player(){

}
public Player(String email, String password, String name, BigDecimal balance, Currency currency) {
    super(email, password);
    this.name = name;
    this.balance = balance;
    this.currency = currency;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public BigDecimal getBalance() {
    return balance;
}

public void setBalance(BigDecimal balance) {
    this.balance = balance;
}

public Currency getCurrency() {
    return currency;
}

public void setCurrency(Currency currency) {
    this.currency = currency;
}

@Override
public String toString() {
    return "Player{" +
            "name='" + name + '\'' +
            ", balance = " + balance +
            ", currency = " + currency +
            '}';
}

}

Класс DefaultSportsBettingService:

    public class DefaultSportsBettingService implements SportsBettingService{

public DummyDataStore dds = new DummyDataStore();
public List <Player> initializedPlayers = dds.getPlayerDatastore();
public List<User> initializedUsers = dds.getUserDataStore();
public List<Outcome> outcomeDatastore = dds.getOutcomeDatastore();
public List<SportEvent> sportEventDataStore = dds.getSportEventDataStore();
public List<Wager> wagerDatastore = dds.getWagerDatastore();
public List<Bet> betsDataStore = dds.getBetDataStore();
Player loggedPlayer;

@Override
public Player authenticateUser(User login) throws AuthenticationException {
    Player find = new Player();

    for (Player player : initializedPlayers) {
            if (login.getEmail().equals(player.getEmail()) && login.getPassword().equals(player.getPassword())) {
                loggedPlayer = player;

            return loggedPlayer;
            }
    }
    throw new AuthenticationException("Incorrect email and/or password");
}

@Override
public List<Bet> findAllBets() {
    return dds.findAllBetVariations();
}

@Override
public Wager createWager(Player player, Outcome outcome, BigDecimal amount) throws LowBalanceException {

    Wager wager = new Wager();
    wager.setOutcome(outcome);
    wager.setPlayer(player);
    wager.setCurrency(player.getCurrency());
    wager.setTimeStampCreated(LocalDateTime.now());
    wager.setAmount(amount);
    if (getLoggedPlayer().getBalance().compareTo(amount) < 0){
        throw new LowBalanceException(loggedPlayer.getBalance().toString(), loggedPlayer.getCurrency());
    }
    getLoggedPlayer().setBalance(getLoggedPlayer().getBalance().subtract(amount));
    if (wager.getOutcome().isWin()){
        wager.setWin(true);
    }
    wagerDatastore.add(wager);
    return wager;
}

@Override
public List<Wager> findAllWagers() {
    return wagerDatastore;
}

@Override
public void calculateResults() {
    BigDecimal counter = BigDecimal.valueOf(0);
    for(int i = 0; i < wagerDatastore.size(); i++){

        if (wagerDatastore.get(i).isWin()){

            counter = counter.add(wagerDatastore.get(i).getOutcome().getOdd().multiply(wagerDatastore.get(i).getAmount()));
            wagerDatastore.get(i).getPlayer().setBalance(counter);
        }

    }
}

public Player getLoggedPlayer() {
    return loggedPlayer;
}

public void setLoggedPlayer(Player loggedPlayer) {
    this.loggedPlayer = loggedPlayer;
}

}

Вам действительно нужно издеваться Player player = mock(Player.class);? Кроме того, зачем вам вообще здесь издеваться? Можете ли вы добавить реализацию классов Player и DefaultSportsBettingService? У вас установлены @RunWith и @ExtendWith mockito или другая библиотека для насмешек?

Dmytro Chasovskyi 16.05.2022 19:40

Это упражнение я должен сделать, однако я еще не чувствую себя как дома в Мочикто.

Mate25 16.05.2022 19:44

Если вы хотите протестировать Сервис, вы не должны издеваться над ним. Макет будет возвращать null каждый раз, если вы не указали when(service.createWager(any(), any(), any()).thenReturn(somethingNotNull);, вы также можете использовать сопоставители, чтобы убедиться, что в метод передаются правильные значения. Но даже если вы добавите поведение, вы просто протестируете макет, ничего не выиграете от подобных тестов.

thinkgruen 16.05.2022 19:48

@Test public void testFindAllBetsIsNotNull(){ DefaultSportsBettingService service = mock(DefaultSportsBettingService.class); assertNotNull(service.findAllBets()); } В этом случае метод не дает сбоя, поэтому объект не является нулевым даже при фиктивном сервисе.

Mate25 16.05.2022 19:53

@ Mate25 Mate25 Добавьте, пожалуйста, полный класс и полный код тестирования. Не только метод тестирования. Еще раз, вы хотите проверить, что createWager работает правильно, верно?

Dmytro Chasovskyi 16.05.2022 19:55

Да, я хочу проверить, правильно ли это работает, однако я с удовольствием выслушаю несколько советов, что я должен проверить и как, так как это мой первый раз, когда я тестирую, и мой единственный надежный источник информации, на который следует полагаться на основе Учебный материал, который я получил, представляет собой связанное видео, которое проверяет очень простую логику.

Mate25 16.05.2022 20:01
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
30
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Несколько выпусков были объединены.

  1. DefaultSportsBettingService — это тестируемый объект, поэтому вы не хотите издеваться над ним.

  2. В вашем случае NullPointerException происходит от getLoggedPlayer, поскольку loggerPlayer никогда не инициализировалось.

Несколько менее важных вещей, которые делают тестирование ужасным:

  1. LocalDateTime.now() является статическим, поэтому вы не можете проверить, правильно ли он установлен, поэтому лучше передать его как внешний параметр (выходящий за рамки этих ответов)

Примерное решение может выглядеть так (не могу протестировать его в IDE):

@ExtendWith(MockitoExtension.class)
class DefaultSportsBettingServiceTest {

    @Mock
    Player loggedPlayer

    @InjectMocks
    DefaultSportsBettingService service

    @Test
    public void testCreateWagerGetsCreated(){
        Mockito.when(loggedPlayer.getBalance()).thenReturn(BigDecimal.ZERO);
        Mockito.doNothing().when(loggedPlayer).setBalance(BigDecimal(15));
        Player player = Player(); // May require more params
        Outcome outcome = new Outcome(null,"description",BigDecimal.valueOf(2),false);
        BigDecimal bd = BigDecimal.valueOf(100);
        assertNotNull(service.createWager(player,outcome, bd));
    }

}

По сути, вы имитируете loggedPlayer, а остальные проходите как обычные объекты и ожидаете, что service.createWager работает правильно. Отсюда Mockito должен предложить вам другие исправления, необходимые для тестирования кода или тестовых значений.

Спасибо за ваши усилия и время @Dmytro Chasovskyi. Вы рекомендуете вместо этого заглушить объект Player?

Mate25 16.05.2022 20:36

@ Mate25 Это зависит. Если вы спрашиваете, стоит ли вам stub loggedPlayer — да, я рекомендую такой подход. Если вы спрашиваете о заглушке плеера, который идет с outcome в качестве параметра - зачем вам это нужно?

Dmytro Chasovskyi 17.05.2022 16:02

Другие вопросы по теме