Buzzet
Buzzet

Reputation: 763

Mock an LinkedList with Mockito and inject it

I am trying to create a LinkList and try to inject it via field injection into the class PlayDeck. After that, I want to mock a method from the CardDeck class.

@Mock
public LinkedList<CardDeck> decks = new LinkedList<>();

@InjectMocks
public PlayDeck mockDeck = new PlayDeck(6);

@Before
public void setup() {
 MockitoAnnotations.initMocks(this);
}
@Test
public void returnADiamond10OnDraw() {
 //given
 this.mockDeck = new PlayDeck(6);
 Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
 BDDMockito.given(this.decks.get(BDDMockito.anyInt()).draw())
     .willReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
 //when
 Card card = this.mockDeck.drawCard();
 //then
 assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
 assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
}

And my PlayDeck class

private LinkedList<CardDeck> decks = new LinkedList<>();

  /**
   * New Playdeck with the amount of decks you want in it
   *
   * @param amount - amount of decks you want to play with
   */
  public PlayDeck(final int amount) {
    for (int i = 0; i < amount; i++) {
      this.decks.add(new CardDeck());
    }
  }
  /**
   * Draws a Card
   *
   * @return Card that was drawn
   */
  public Card drawCard() {
    int randomInt = new Random().nextInt(this.decks.size());
    return this.decks.get(randomInt).draw();
  }

And the CardDeck class

List<Card> deck;

public Card draw() {
    final int randomInt = new Random().nextInt(51);
    return this.deck.remove(randomInt);
  }

The problem here is that I get a NullPointerException every time I run the test. I think it happens because my LinkedList decks are null. But it should get populated through the PlayDeck constructor.

Does anyone know how to fix this? Thanks!

Edit: Stacktrace:

java.lang.NullPointerException
    at com.buzzet.test.PlayDeckShould.returnADiamond10OnDraw(PlayDeckShould.java:68)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Upvotes: 0

Views: 512

Answers (1)

Sagar Gangwal
Sagar Gangwal

Reputation: 7965

Try below code, i had refactored some of lines.

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;

public class PlayDeckShould {
    @Mock
    public LinkedList<CardDeck> decks = new LinkedList<>();
    
    @Mock
    public CardDeck cardDeck;
    
    @InjectMocks
    public PlayDeck mockDeck = new PlayDeck(6);
    
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }
    
    
    @Test
    public void returnADiamond10OnDraw() {
        //givens
        decks=this.mockDeck.decks;
        Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
        when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
        when(decks.get(anyInt())).thenReturn(cardDeck);
        when(decks.size()).thenReturn(6);
        when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
        Card card = this.mockDeck.drawCard();
        assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
        assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
    }

Instead of Mocking Deck, you simply need to call that mockDeck.getDecks().

You had populated that deck inside of CardDack class so you need to call getter method of same attribute of that CardDack object.

Upvotes: 1

Related Questions