【问题标题】:Mocking an enum using Mockito?使用 Mockito 模拟枚举?
【发布时间】:2016-05-05 11:17:27
【问题描述】:

我需要模拟以下枚举:

public enum PersonStatus
{
    WORKING,
    HOLIDAY,
    SICK      
}

这是因为它在我正在测试的以下类中使用:

待测类:

public interface PersonRepository extends CrudRepository<Person, Integer>
{
    List<Person> findByStatus(PersonStatus personStatus);
}

这是我目前的测试尝试:

当前测试:

public class PersonRepositoryTest {

    private final Logger LOGGER = LoggerFactory.getLogger(PersonRepositoryTest.class);

    //Mock the PersonRepository class
    @Mock
    private PersonRepository PersonRepository;

    @Mock
    private PersonStatus personStatus;

    @Before
    public void setUp() throws Exception {

        MockitoAnnotations.initMocks(this);
        assertThat(PersonRepository, notNullValue());
        assertThat(PersonStatus, notNullValue());
    }

    @Test
    public void testFindByStatus() throws ParseException {

        List<Person> personlist = PersonRepository.findByStatus(personStatus);
        assertThat(personlist, notNullValue());
    }
}

这会导致以下错误:

错误:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class PersonStatus
Mockito cannot mock/spy following:
  - final classes
  - anonymous classes
  - primitive types

我该如何解决这个问题?

【问题讨论】:

  • 确定你需要模拟PersonStatus吗?你不能只使用实际的实例吗?
  • 我认为您不想模拟枚举 - 您想在测试中传递枚举的各种值并检查结果是否符合预期。
  • @assylias 请提供答案,说明如何这样做
  • 为什么要模拟枚举?
  • 您只需要传递PersonStatus.WORKINGPersonStatus.SICK 之类的参数即可。不管它是什么,然后用你的预期结果进行检查。

标签: java unit-testing enums mockito final


【解决方案1】:

只是为了完成图片:

最新版本的 Mockito 2 很好地支持模拟 final 类。但您必须先明确启用这个新的实验性功能!

(请参阅 here 了解如何做到这一点 - 归结为将文件 mockito-extensions/org.mockito.plugins.MockMaker 添加到您的类路径中,其中包含值 mock-maker-inline

当然:你只在必要时嘲笑某些东西。您模拟 Enum 实例的愿望很可能是由于不理解这一点 - 或者因为您在这里创建了难以测试的代码。从这个意义上说,真正的答案是首先寻找避免这种嘲笑的方法。

【讨论】:

  • 这应该是公认的答案,即使可以在不模拟枚举的情况下处理 OPs 案例。
  • 有相同的场景并最终将我需要的信息从枚举传递到方法,以便该方法可以使用我可以操作的参数进行测试。从fooMethod(FooEnum myEnum)fooMethod(String data1FromEnum, Stirng data2fromEnum)。在我看来,现在更容易测试但不太干净,特别是如果你有很多或参数。如果你有很多,宁愿使用 DTO 对象,你也可以像 fooMethod(DtoClassWithEnumVars dto); 那样模拟它
【解决方案2】:

您的testFindByStatus 试图断言findByStatus 不返回null。

如果无论personStatus 参数的值如何,方法都以相同的方式工作,则只需传递其中一个:

@Test
public void testFindByStatus() throws ParseException {
    List<Person> personlist = PersonRepository.findByStatus(WORKING);
    assertThat(personlist, notNullValue());
}

如果其他可能值的行为可能不同,您可以测试它们中的每一个:

@Test
public void testFindByStatus() throws ParseException {
    for (PersonStatus status : PersonStatus.values()) {
        List<Person> personlist = PersonRepository.findByStatus(status);
        assertThat(personlist, notNullValue());
    }
}

【讨论】:

  • 你是如何解决 org.mockito.exceptions.base.MockitoException 的?从你的回答中我不明白。
  • @AlessandroC OP 试图模拟一个触发异常的枚举。在我的回答中,我建议不要模拟枚举,这样可以解决问题
  • 啊,好吧...不幸的是,这并不能解决我的问题,但感谢您的反馈!
【解决方案3】:

如前所述,使用 Mockito 2 并启用实验性功能。

实际上缺少的是一个示例 sn-p 来演示如何。 考虑到一个名为 LicenseHistoryAction 的枚举具有 4 个已经存在的值,这将正确地模拟一个 UNSUPPORTED 一个:

try (MockedStatic<LicenseHistoryAction> licenseHistoryActionMockedStatic = Mockito.mockStatic(LicenseHistoryAction.class)) {
    final LicenseHistoryAction UNSUPPORTED = Mockito.mock(LicenseHistoryAction.class);
    Mockito.doReturn(4).when(UNSUPPORTED).ordinal();

    licenseHistoryActionMockedStatic.when(LicenseHistoryAction::values)
            .thenReturn(new LicenseHistoryAction[]{
                    LicenseHistoryAction.ASSIGN,
                    LicenseHistoryAction.RELEASE,
                    LicenseHistoryAction.UNBIND,
                    LicenseHistoryAction.DENY,
                    UNSUPPORTED});
}

【讨论】:

    猜你喜欢
    • 2020-05-25
    • 2013-04-03
    • 2022-07-29
    • 2015-07-19
    • 1970-01-01
    • 2022-07-07
    • 1970-01-01
    相关资源
    最近更新 更多