【问题标题】:Unit testing Java switch - case logic - multiple separate functions or multiple calls单元测试 Java 开关 - 案例逻辑 - 多个单独的函数或多个调用
【发布时间】:2015-12-16 13:15:09
【问题描述】:

下面是我必须为其编写单元测试的类之一中的示例 switch 语句。我已经从下面的代码中删除了每种情况下的逻辑。

switch (insurance.getInsuranceType()) {
                case None:{
                    break;}

                case Health: {

                    break;}

                case Auto:{
                    break;}

                case WorkersCompensation:{
                    break;}

                default:{}

            }

我必须覆盖每个开关路径,但要到达要测试的函数中的这个开关点,我必须放置 10 条 whens 和相应的验证语句(我正在使用 Mockito 进行模拟)。为了覆盖每条路径,我可以选择编写与 switch 语句中的情况一样多的函数(针对各种 InsuranceType 数据),或者我编写单个函数并通过更改 InsuranceTypedata 来重复相同的代码。测试代码以两种方式重复,第二种方式更容易出错,用于验证对模拟对象的调用。我的问题是关于任何其他方式(有助于避免重复代码和干净的测试代码)以及经验丰富的开发人员如何在他们的单元测试中处理 switch 语句(因为我的代码中有 10 个案例的情况)?代码是由其他一些开发人员编写的,我被要求编写单元测试以增加测试覆盖率并进行额外的单元测试。我需要知道是否有关于多个逻辑分支的通用实践(不一定只针对 switch 语句,但有时也有多个 if - else if - else 逻辑和 3 -4 级深度嵌套条件)。 insurance.getInsuranceType() 是一个枚举。 请建议。

【问题讨论】:

    标签: java unit-testing junit mockito


    【解决方案1】:

    免责声明:这是一种观点,但我将其表述为答案,因为评论不足以完全解释我自己。

    一般来说,switch 语句表示代码设计不佳。以上述情况为例:

    public Coverage returnCoverage() {  // I'm just making up a method name here
        switch (insurance.getInsuranceType()) {
            case None: {
                ...
                break;
            }
            case Health: {
                ...
                break;
            }
            ...
        }
    }
    

    ...看起来您有一些方法,其逻辑分支在保险类型上。这向我表明,您的保险类型实际上应该具有逻辑。例如:

    public interface InsuranceType {    // not enum
        Coverage getCoverage();
    }
    
    public class NoInsurance implements InsuranceType {
        public Coverage getCoverage() {
            ...
        }
    }
    
    public class HealthInsurance implements InsuranceType {
        public Coverage getCoverage() {
            ...
        }
    }
    
    // etc.
    

    然后,您的Insurance 对象将包含InsuranceType 的一个实例,就像它现在一样。你可以用enums 做同样的事情——每个枚举值实现一个不同的方法——但这有点混乱。

    如果您对所有switch 语句执行此操作,您应该会看到一个连贯的InsuranceType 域对象开始出现,并且您应该开始看到可以移动到该类层次结构中的其他代码。此外,如果您将来需要添加一种新的保险类型,您不必搜索所有代码试图找到您打开InsuranceType 的所有位置——相反,您只需创建一个新的实现类,一切都神奇地起作用。

    要回答您关于测试的问题,如果您执行上述操作,那么您的 switch 语句就会消失。因此,您可以单独测试每个 InsuranceTypes,而无需进行大量模拟。

    高度嵌套的 if 语句也是如此。将它们分解为单独的方法,并将逻辑移动到它所属的位置,然后合并它。您通常会发现很多分支非常相似的剪切“n”粘贴代码。如果您使用 IDE,请查找提取方法重构,并确保选择“检测重复项”选项。希望您可以减少必须维护的代码量和代码的复杂性,并将其保持在更好的状态以供下一个开发人员维护!

    希望有帮助!

    【讨论】:

    • 干得好!虽然一个意见这实际上是一个非常好的建议。
    • @Eric - 感谢您的建议。不幸的是,我可以提出更改代码的建议,但这取决于是否获得批准。
    • @Sabir_Khan 唉。您能否将 Martin Fowler 的 Refactoring 或 Robert Martin 的 Clean Code 或 Eric Evans 的 Domain-Driven Design 的副本交给审批者? :)
    • @EricGalluzzo - 首先,让我自己读一下 :) 我的意思是,批准者对建议非常开放,但有一个过程。
    • 这里的另一个想法是在代码之前编写测试,因为它会减少编写 switch 语句开始的可能性。
    猜你喜欢
    • 2019-07-22
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 2014-09-29
    • 1970-01-01
    相关资源
    最近更新 更多