英文:
Mock an LinkedList with Mockito and inject it
问题
我正在尝试创建一个 LinkList<CardDeck>,并尝试通过字段注入将其注入到 PlayDeck 类中。之后,我想模拟 CardDeck 类中的一个方法。
@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());
}
我的 PlayDeck 类如下:
private LinkedList<CardDeck> decks = new LinkedList<>();
/**
* 新的 Playdeck,其中包含您希望在其中玩的牌组数量
*
* @param amount - 您想玩的牌组数量
*/
public PlayDeck(final int amount) {
for (int i = 0; i < 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<Card> 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<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)
答案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<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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论