Mockito / PowerMock什么时候......然后没被调用?

时间:2014-07-09 18:46:05

标签: junit mockito junit4 powermock

当我执行以下测试时,将返回原始对象而不是模拟,因此正在执行实际方法 getLevelCriteriaForLevel(level)(我在调试器中观察到)。为什么会这样?我很确定昨天这已经奏效了,而且我没有改变任何东西。

我已经尝试了

@PrepareForTest({LevelCriteria.class, LevelGenerator.class})

或者像以前一样使用MockitoJunitRunner,但这也没有帮助。 这是代码(generateConcreteLevel是一个私有方法。只有当我从mock传递这个数据时才抛出预期的异常。否则它不被抛出。测试失败,因为没有抛出异常,因为测试没有&# 39;使用模拟对象,但使用真实对象):

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

和测试...

@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的Whitebox执行私有方法,我将在重构后执行该操作,但问题是,为什么......当时在这里不起作用。

2 个答案:

答案 0 :(得分:0)

假设您的问题是:

  

为什么在我希望有模拟实现时执行真正的方法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

我没有使用@PrepareForTestPowerMockRunner。我有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 ......为什么会出现问题? Eclipse是一个很棒的IDE。

答案 1 :(得分:0)

我发现了什么是错的。不幸的是,你没有看到这个问题中的真正问题,因为我简化了类:

我的LevelGenerator真正实现了今天的参数化构造函数。这就是为什么它在昨天工作但不再存在的原因。显然,当不使用标准构造函数时,Mockito会出现模拟注入问题。

结果:时间...然后按预期工作。