用Mockito模拟一个链表并注入它。

huangapple go评论64阅读模式
英文:

Mock an LinkedList with Mockito and inject it

问题

我正在尝试创建一个 LinkList<CardDeck>,并尝试通过字段注入将其注入到 PlayDeck 类中。之后,我想模拟 CardDeck 类中的一个方法。

@Mock
public LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();

@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());
}

我的 PlayDeck 类如下:

private LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();

  /**
   * 新的 Playdeck,其中包含您希望在其中玩的牌组数量
   *
   * @param amount - 您想玩的牌组数量
   */
  public PlayDeck(final int amount) {
    for (int i = 0; i &lt; amount; i++) {
      this.decks.add(new CardDeck());
    }
  }
  /**
   * 抽取一张牌
   *
   * @return 被抽取的牌
   */
  public Card drawCard() {
    int randomInt = new Random().nextInt(this.decks.size());
    return this.decks.get(randomInt).draw();
  }

以及 CardDeck 类:

List&lt;Card&gt; deck;

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

问题在于每次运行测试时都会出现 NullPointerException。我认为这是因为我的 LinkedList decks 为 null。但它应该通过 PlayDeck 构造函数进行填充。

有谁知道如何修复这个问题吗?谢谢!

编辑:
堆栈跟踪:

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)
英文:

I am trying to create a LinkList<CardDeck> 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&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();

@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&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();

  /**
   * 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 &lt; 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&lt;Card&gt; 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)

答案1

得分: 1

尝试以下代码,我已经重构了一些行。

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.getDecks();
        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());
    }
}

而不是模拟 Deck,你只需要调用 mockDeck.getDecks()

你已经在 CardDeck 类内部填充了那个 deck,所以你需要调用 CardDeck 对象的同名属性的 getter 方法

英文:

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&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
    
    @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.

huangapple
  • 本文由 发表于 2020年8月20日 02:05:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63492626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定