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

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

Mock an LinkedList with Mockito and inject it

问题

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

  1. @Mock
  2. public LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
  3. @InjectMocks
  4. public PlayDeck mockDeck = new PlayDeck(6);
  5. @Before
  6. public void setup() {
  7. MockitoAnnotations.initMocks(this);
  8. }
  9. @Test
  10. public void returnADiamond10OnDraw() {
  11. //given
  12. this.mockDeck = new PlayDeck(6);
  13. Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
  14. BDDMockito.given(this.decks.get(BDDMockito.anyInt()).draw())
  15. .willReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  16. //when
  17. Card card = this.mockDeck.drawCard();
  18. //then
  19. assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
  20. assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
  21. }

我的 PlayDeck 类如下:

  1. private LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
  2. /**
  3. * 新的 Playdeck,其中包含您希望在其中玩的牌组数量
  4. *
  5. * @param amount - 您想玩的牌组数量
  6. */
  7. public PlayDeck(final int amount) {
  8. for (int i = 0; i &lt; amount; i++) {
  9. this.decks.add(new CardDeck());
  10. }
  11. }
  12. /**
  13. * 抽取一张牌
  14. *
  15. * @return 被抽取的牌
  16. */
  17. public Card drawCard() {
  18. int randomInt = new Random().nextInt(this.decks.size());
  19. return this.decks.get(randomInt).draw();
  20. }

以及 CardDeck 类:

  1. List&lt;Card&gt; deck;
  2. public Card draw() {
  3. final int randomInt = new Random().nextInt(51);
  4. return this.deck.remove(randomInt);
  5. }

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

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

编辑:
堆栈跟踪:

  1. java.lang.NullPointerException
  2. at com.buzzet.test.PlayDeckShould.returnADiamond10OnDraw(PlayDeckShould.java:68)
  3. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  4. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  5. at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  6. at java.base/java.lang.reflect.Method.invoke(Method.java:567)
  7. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  8. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  9. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  10. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  11. at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
  12. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  13. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  14. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  15. at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  16. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  17. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  18. at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  19. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  20. at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  21. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  22. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
  23. at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
  24. at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
  25. 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.

  1. @Mock
  2. public LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
  3. @InjectMocks
  4. public PlayDeck mockDeck = new PlayDeck(6);
  5. @Before
  6. public void setup() {
  7. MockitoAnnotations.initMocks(this);
  8. }
  9. @Test
  10. public void returnADiamond10OnDraw() {
  11. //given
  12. this.mockDeck = new PlayDeck(6);
  13. Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
  14. BDDMockito.given(this.decks.get(BDDMockito.anyInt()).draw())
  15. .willReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  16. //when
  17. Card card = this.mockDeck.drawCard();
  18. //then
  19. assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
  20. assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
  21. }

And my PlayDeck class

  1. private LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
  2. /**
  3. * New Playdeck with the amount of decks you want in it
  4. *
  5. * @param amount - amount of decks you want to play with
  6. */
  7. public PlayDeck(final int amount) {
  8. for (int i = 0; i &lt; amount; i++) {
  9. this.decks.add(new CardDeck());
  10. }
  11. }
  12. /**
  13. * Draws a Card
  14. *
  15. * @return Card that was drawn
  16. */
  17. public Card drawCard() {
  18. int randomInt = new Random().nextInt(this.decks.size());
  19. return this.decks.get(randomInt).draw();
  20. }

And the CardDeck class

  1. List&lt;Card&gt; deck;
  2. public Card draw() {
  3. final int randomInt = new Random().nextInt(51);
  4. return this.deck.remove(randomInt);
  5. }

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:

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

答案1

得分: 1

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

  1. import static org.assertj.core.api.Assertions.assertThat;
  2. import static org.mockito.ArgumentMatchers.anyInt;
  3. import static org.mockito.Mockito.when;
  4. public class PlayDeckShould {
  5. @Mock
  6. public LinkedList<CardDeck> decks = new LinkedList<>();
  7. @Mock
  8. public CardDeck cardDeck;
  9. @InjectMocks
  10. public PlayDeck mockDeck = new PlayDeck(6);
  11. @Before
  12. public void setup() {
  13. MockitoAnnotations.initMocks(this);
  14. }
  15. @Test
  16. public void returnADiamond10OnDraw() {
  17. //givens
  18. decks = this.mockDeck.getDecks();
  19. Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
  20. when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  21. when(decks.get(anyInt())).thenReturn(cardDeck);
  22. when(decks.size()).thenReturn(6);
  23. when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  24. Card card = this.mockDeck.drawCard();
  25. assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
  26. assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
  27. }
  28. }

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

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

英文:

Try below code, i had refactored some of lines.

  1. import static org.assertj.core.api.Assertions.assertThat;
  2. import static org.mockito.ArgumentMatchers.anyInt;
  3. import static org.mockito.Mockito.when;
  4. public class PlayDeckShould {
  5. @Mock
  6. public LinkedList&lt;CardDeck&gt; decks = new LinkedList&lt;&gt;();
  7. @Mock
  8. public CardDeck cardDeck;
  9. @InjectMocks
  10. public PlayDeck mockDeck = new PlayDeck(6);
  11. @Before
  12. public void setup() {
  13. MockitoAnnotations.initMocks(this);
  14. }
  15. @Test
  16. public void returnADiamond10OnDraw() {
  17. //givens
  18. decks=this.mockDeck.decks;
  19. Card givenCard = Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build();
  20. when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  21. when(decks.get(anyInt())).thenReturn(cardDeck);
  22. when(decks.size()).thenReturn(6);
  23. when(cardDeck.draw()).thenReturn(Card.builder().color(CardColor.Diamond).face(CardFace.TEN).build());
  24. Card card = this.mockDeck.drawCard();
  25. assertThat(card.getFace()).isEqualByComparingTo(givenCard.getFace());
  26. assertThat(card.getColor()).isEqualByComparingTo(givenCard.getColor());
  27. }

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:

确定