mockito java中switch case中无法到达的default子句的覆盖

s5a0g9ez  于 2023-05-17  发布在  Java
关注(0)|答案(2)|浏览(202)

我有下面的代码片段,我不确定如何用单元测试覆盖default子句。

public Block solve(String str) {

    try {
            
        final BlockType blockType = BlockType.valueOf(str);

        switch (blockType) {
            case TEXTBLOCK:
                return ...
            case IMAGEBLOCK:
                return ...
            default:
                return null;
        }
    } catch (final IllegalArgumentException e) {
        return null;
    }
}
@AllArgsConstructor
public enum BlockType {
    IMAGEBLOCK("imageBlock"),
    TEXTBLOCK("textBlock");

    private String value;
}

注意:我有一个限制,即solve方法中的参数必须是String类型。另外,我不想仅仅为了测试目的而在枚举中添加任何虚拟值。

pgky5nke

pgky5nke1#

如果默认情况确实是不可访问的(就像您的情况一样),您有两个选择:
1.你就放下吧。
1.抛出错误而不是返回null

switch( blockType ) 
{
    case TEXTBLOCK:
        return ...
    case IMAGEBLOCK:
        return ...
    default: throw new AssertionError( "Invalid blockType: " + blockType.name() );
}

在这种情况下,你很快就知道,如果你添加一个额外的BlockType枚举值,而不是一些虚假的NullPointerExceptions发生在远离switch的地方,有些东西就不起作用了。
关于你最初的问题:如果不大量修改代码,就无法测试它。但对于像这种默认标签的“安全网”来说,这并不罕见。

6ovsh4lw

6ovsh4lw2#

在您的示例中,有一种方法可以覆盖default案例。但确实很恶心。
首先,我们需要理解为什么示例中的default案例没有标记为无法访问的代码。这是JLS 13.4.26中规定的enum类演化规则的逻辑结果。这说明向现有的enum添加额外的常量不会破坏二进制兼容性。
因此,虽然在你的例子中的default分支在代码被编译的时候是不能有效地访问的,但是如果稍后在enum中添加另一个常量,它就可以变得可访问。而且Java编译器 * 不会 * 将default分支标记为无法访问的代码……你也看到了!
所以......在示例中获得default分支的100%单元测试覆盖率的“讨厌”方法就是模拟代码的演变。编写enum类的另一个版本,其中包含一个额外的常量,然后编写一个单元测试,将该常量提供给带有switch语句的代码。
另外,我不想仅仅为了测试目的而在枚举中添加任何虚拟值。
不是这样的我们正在做的是模拟enum的(假设的)* 未来 * 版本。当前版本没有额外的常量。
如何使其在典型的单元测试框架和典型的Java构建工具的上下文中工作,留给读者作为练习。
这样做好吗?IMO不!最好是承认它是(通常)不值得去极端“实现”100%的覆盖率.事实上,如果您的代码中有一个“这永远不应该发生”的情况,那么在测试期间尝试使该情况实际发生是没有价值的。
但是......如果你的应用程序的设计目标是 * 处理 * enum的演变,那么实现对无法访问的default情况的覆盖可能是合理的。
然而...在这种情况下返回null确实是个坏主意;查看评论和上面的答案,了解原因,以及你可以做些什么。

相关问题