带有默认分支的 JUnit 代码覆盖率 switch 语句

问题描述 投票:0回答:2

我有 util 方法来处理一些文本。处理方式由

enum Mode
决定。在编写单元测试来覆盖此方法时,我必须添加虚拟
enum
元素,以便将
default
语句的
switch
部分包含到测试中。默认部分是我检查
enum
是否被新元素扩展并且该新元素未添加到
switch
语句中的情况,这意味着该新元素无法进行处理。如果我删除虚拟元素并尝试使用
null
,那么我会得到 NPE,并且 Java 甚至不会输入
switch
语句 - 这是当您使用
null
表示
switch
语句时的正常行为。

问题: 有没有办法避免在单元测试中添加虚拟

enum
元素,但仍覆盖
default
语句的
switch
部分?

为了清晰起见,添加了:Java 17、JUnit Jupiter 5、Eclipse 代码覆盖工具

代码

abstract class LineBreaker {

    public enum Mode {
        LAST_SPACES,
        LAST_CHARS,
        DUMMY
    }

    public static String process(
        final String text,
        final LineBreaker.Mode mode,
        final int amount
    ) {
        switch (mode) {
            case LAST_SPACES : {
                // blah blah create `processingResult`
                return processingResult;
            }
            case LAST_CHARS : {
                // blah blah create `processingResult`
                return processingResult;
            }
            default :
                throw new IllegalStateException(
                    "Processor for " +
                        LineBreaker.class.getSimpleName() + "." +
                        LineBreaker.Mode.class.getSimpleName() + "." +
                        mode.name() +
                        " not implemented"
                );
        }
    }

}

单元测试

@Test
void testLineBreakerException() {
    assertThrows(
        IllegalStateException.class,
        () -> LineBreaker.process( "Dog", LineBreaker.Mode.DUMMY, 10 ),
        "Expected " + IllegalStateException.class.getSimpleName()
    );
}

无需额外虚拟枚举元素的单元测试

无需额外的虚拟枚举元素即可实现代码覆盖率


使用附加虚拟枚举元素进行单元测试

无需额外的虚拟枚举元素即可实现代码覆盖率

java unit-testing junit code-coverage
2个回答
1
投票

您不需要创建或扩展现有的

enum Mode
。你只需要使用 Mockito 来模拟这个枚举即可。
为此,您可以使用Mockito版本5或更高版本,它支持mockito-inline作为默认的mockmaker。这将轻松支持模拟静态方法。

testImplementation 组:'org.mockito',名称:'mockito-core',版本:'5.11.0'

策略是创建一个模拟枚举

UNSUPPORTED
。使用
Mockito.mockStatic
模拟枚举的静态方法
values()
,并返回现有值加上模拟枚举
UNSUPPORTED

然后这个模拟
UNSUPPORTED
枚举将触发 switch-case 语句的默认路径,这使您可以轻松地执行断言。

代码片段


import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doReturn;

public class SOEnumQuestionTest {

    public enum Mode {
        LAST_SPACES,
        LAST_CHARS
    }

    public static String process(final Mode mode) {
        switch (mode) {
            case LAST_SPACES : {
                return "processing last spaces";
            }
            case LAST_CHARS : {
                return "processing last chars";
            }
            default :
                throw new IllegalStateException("Processor not implemented");
        }
    }

    @Test
    public void testProcessWithDefaultSwitchCase() {
        try (MockedStatic<Mode> dummyModeMockedStatic = Mockito.mockStatic(Mode.class)) {
            final Mode UNSUPPORTED = Mockito.mock(Mode.class);
            // We want to give the mocked enum in the last position of the enum values list
            // E.g: Enum has 2 values -> our mock UNSUPPORTED enum index is 2
            doReturn(2).when(UNSUPPORTED).ordinal();
            dummyModeMockedStatic.when(Mode::values)
                    .thenReturn(new Mode[]{
                            Mode.LAST_SPACES,
                            Mode.LAST_CHARS,
                            UNSUPPORTED});

            Throwable expectedException = assertThrows(IllegalStateException.class, () -> SOEnumQuestionTest.process(UNSUPPORTED));
            assertEquals("Processor not implemented", expectedException.getMessage());
        }
    }
}


0
投票

由于您使用的是 Java 17 并且您的分支正在返回一个值,因此您可以使用 switch 表达式,它必须是详尽的(因此编译器将检查您是否涵盖了所有情况)。

    public static String process(
            final String text,
            final LineBreaker.Mode mode,
            final int amount
    ) {
        String result = switch (mode) {
            case LAST_SPACES -> "some processing result";
            case LAST_CHARS -> "another result";
        };

        return result;
    }

这样,您就不需要默认分支或测试。

© www.soinside.com 2019 - 2024. All rights reserved.