当我执行以下测试时,返回的是原始对象而不是模拟对象,因此执行的是真正的方法getLevelCriteriaForLevel(level)(我在调试器中观察到这一点)。为什么会这样呢?我很确定这个昨天已经工作了,我没有改变任何东西。
I already tried
@PrepareForTest({LevelCriteria.class, LevelGenerator.class})
或者像我以前那样使用MockitoJunitRunner,但这也没有帮助。下面是代码(generateConcreteLevel是一个私有方法。只有当我从模拟传递此数据时,才会抛出预期的异常。否则它不会被抛出。测试失败是因为没有抛出异常,因为测试没有使用模拟对象,而是使用真实对象):
public class LevelGenerator
{
public void createLevel(int level)
{
generateConcreteLevel(levelCriteria.getLevelCriteriaForLevel(level));
}
private void generateConcreteLevel(LevelCriterion levelCriterion)
{
int entryGroupCount = levelCriterion.getEntryGroupCount();
int exitGroupCount = levelCriterion.getExitGroupCount();
int exitsWhileEntries = levelCriterion.getExitsWhileEntries();
int maxGroupSize = levelCriterion.getMaxGroupSize();
List<Question> questions = levelCriterion.getQuestions();
int speed = levelCriterion.getSpeed();
Range blueItemsCount = levelCriterion.getBlueItemsCount();
Range brownItemsCount = levelCriterion.getBrownItemsCount();
Range greenItemsCount = levelCriterion.getGreenItemsCount();
Range redItemsCount = levelCriterion.getRedItemsCount();
Range whiteItemsCount = levelCriterion.getWhiteItemsCount();
Range timespanBetweenGroups = levelCriterion.getTimespanBetweenGroups();
float fractionOfCarAmountToLeave = levelCriterion.getFractionOfCarAmountToLeave();
float fractionOfMinimumItemsAmountInCarParkToStartExits = levelCriterion.getFractionOfMinimumItemsAmountInCarParkToStartExits();
checkItemsFitInEntryGroups(entryGroupCount, maxGroupSize, blueItemsCount, brownItemsCount, greenItemsCount, redItemsCount, whiteItemsCount);
}
private void checkItemsFitInEntryGroups(int entryGroupCount, int maxGroupSize, Range... ranges)
{
int totalRangeCount = 0;
for (Range range : ranges)
{
totalRangeCount += range.getMaximum();
}
if (totalRangeCount > entryGroupCount * maxGroupSize)
{
throw new UnsupportedOperationException("Error in level criterion: Not enough entry groups for Items.");
}
}
}
和test…
@RunWith(PowerMockRunner.class)
public class LevelGeneratorTest
{
@Mock
private LevelCriteria levelCriteriaMock;
@InjectMocks
private LevelGenerator levelGenerator;
@Test(expected=UnsupportedOperationException.class)
public void tooLessPositionsInEntryGroups()
{
LevelCriterion levelCriterion = new LevelCriterion.LevelCriterionBuilder()
.withBlueItemsCount(new Range(10, 10))
.withEntryGroupCount(3)
.withExitGroupCount(3)
.withMaxGroupSize(3)
.build();
when(levelCriteriaMock.getLevelCriteriaForLevel(anyInt())).thenReturn(levelCriterion);
levelGenerator.createLevel(0);
}
}
顺便说一下:这不是Eclipse的问题,因为Maven构建会产生相同的错误。我知道我可以用PowerMockito的白盒直接执行私有方法,我将在重构后做什么,但问题是,为什么当…
假设你的问题是:
为什么真正的方法getLevelCriteriaForLevel(level)执行时,我期望有模拟的实现?
我将试着证明,如果你复制它是一个简单的例子(如果你需要从你当前的工作空间切换),一切工作都如预期的那样好。
我没有您的LevelCriterion.LevelCriterionBuilder()
,所以我通过实例化LevelCriterion
(空对象)来简化您的测试。这是不相关的,因为在我的实现中,我将始终返回一个UnsupportedOperationException。
这是我的LevelGenerator的样子。UnsupportedOperationException是尽可能简单的LevelGenerator#generateConcreteLevel(LevelCriterion)。
如果这样实现:
public class LevelGenerator
{
LevelCriteria levelCriteria;
public void createLevel(int level)
{
generateConcreteLevel(levelCriteria.getLevelCriteriaForLevel(level));
}
private void generateConcreteLevel(LevelCriterion levelCriteriaForLevel)
{
throw new UnsupportedOperationException("xxx");
}
}
测试是绿色的,使用@RunWith(MockitoJUnitRunner.class)
在LevelGeneratorTest
之上。
我没有用@PrepareForTest
或PowerMockRunner
。我有Mockito 1.9.5版本。
我确信我没有使用真正的getLevelCriteriaForLevel(level)
实现,因为它看起来像这样:
public class LevelCriteria {
public LevelCriterion getLevelCriteriaForLevel(int level) {
throw new IllegalStateException("Unexpected call");
}
}
如果真正的getLevelCriteriaForLevel(int)被执行,测试是红色的(因为抛出了一个IllegalStateException)。
和测试仍然是绿色的…
这适用于纯mockito(1.9.5版本)方法。你应该删除所有其他模拟库(PowerMock, EasyMock…)
你确定你的when(..).thenReturn(..)
的静态调用是Mockito的一个吗?
你试过了吗:Mockito.when(..).thenReturn(..)
我希望这对你有帮助。
PS:我看到你更新了问题。这对我来说有点不公平,但我不会再更新我的答案了。我不需要generateConcreteLevel(..)
的实现细节来说明when(..)
调用正在工作。再读一遍我的回答。在一个单独的工作空间里试试,你会自己看到的。
PS-2:我也在用Eclipse…为什么会有问题呢?
我知道是怎么回事了。不幸的是,您没有看到这个问题的真正问题,因为我简化了这些类:
今天我真正的LevelGenerator实现了一个参数化的构造函数。这就是为什么昨天还行,现在不行了。显然,当不使用标准构造函数时,Mockito存在模拟注入问题。
结果:when…然后按预期工作