【问题标题】:Repeating code in JUnit tests在 JUnit 测试中重复代码
【发布时间】:2012-02-20 09:47:20
【问题描述】:

在测试类中复制代码是“坏事”吗?如您所见,我将驾驶记录添加到驾驶日志中,以便通过多种方法进行测试。将其提取到私有辅助方法是否更好,还是保持原样更清晰?在这种情况下你会怎么做?

@Test
public void shouldRemoveAllDrivingRecords() {
    Duration duration1 = new Duration(1, 30, 45);
    Duration duration2 = new Duration(2, 50, 12);

    DrivingRecord drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
    DrivingRecord drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");

    drivingLog.addDrivingRecord(drivingRecord1);
    drivingLog.addDrivingRecord(drivingRecord2);

    drivingLog.removeAllDrivingLogs();

    assertEquals(0, drivingLog.numberOfDrivingRecords());
}

@Test
public void shouldSumTheDistanceDriven() {
    Duration duration1 = new Duration(1, 30, 45);
    Duration duration2 = new Duration(2, 50, 12);

    DrivingRecord drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
    DrivingRecord drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");

    drivingLog.addDrivingRecord(drivingRecord1);
    drivingLog.addDrivingRecord(drivingRecord2);

    double expectedDistanceDriven = drivingRecord1.getDistance() + drivingRecord2.getDistance();
    double totalDistanceDriven = drivingLog.getDistanceDriven();

    assertEquals(expectedDistanceDriven, totalDistanceDriven, 0.1);
}

【问题讨论】:

    标签: java unit-testing jakarta-ee junit


    【解决方案1】:

    您可以使用@org.junit.Before 注释方法并初始化该方法中的变量:

    public class DrivingLogTest { 
         //suposing DrivingLog class...
         private DrivingLog drivingLog;
    
         private Duration duration1;
         private Duration duration2;
    
         private DrivingRecord drivingRecord1;
         private DrivingRecord drivingRecord2;
    
    
        @Before 
        public void setUp() { 
           drivingLog=new DrivingLog();
           duration1 = new Duration(1, 30, 45);
           duration2 = new Duration(2, 50, 12);
    
           drivingRecord1 = new DrivingRecord(230.0, duration1, "This was a long trip");
           drivingRecord2 = new DrivingRecord(300.0, duration2, "This trip is even longer.");
    
           drivingLog.addDrivingRecord(drivingRecord1);
           drivingLog.addDrivingRecord(drivingRecord2);
    
        }
    
    
        @Test
        public void shouldRemoveAllDrivingRecords() {
    
           drivingLog.removeAllDrivingLogs();
    
           assertEquals(0, drivingLog.numberOfDrivingRecords());
        }
    
        @Test
        public void shouldSumTheDistanceDriven() {
    
           double expectedDistanceDriven = drivingRecord1.getDistance() +  drivingRecord2.getDistance();
           double totalDistanceDriven = drivingLog.getDistanceDriven();
    
           assertEquals(expectedDistanceDriven, totalDistanceDriven, 0.1);
        }
    }
    

    【讨论】:

      【解决方案2】:

      我敢于不同意大多数答案,并且对我来说测试代码与生产代码相同。当然,测试代码与生产代码一样值得关注和关注,因为它是整体开发工作的一部分,但它们在性质上有所不同。我不会重复自己,而是指出我的另一个答案:Is it OK to copy past unit test when logic is the same

      也就是说,重复创建测试数据是不好的。更好的是考虑为测试精心创建的数据集,并支持大多数情况下的测试。该数据集可以在setUp 方法中创建。如有必要,可以有多个测试数据集,涵盖业务规则的变体。创建有用的测试数据集并不容易,但值得花一些时间在上面。此外,测试数据可以从 JSON 左右加载。在某些情况下,它更容易维护。

      单元测试通常不应相互依赖。但通常,测试用例确实相互依赖。例如,要测试一个列表,需要测试add() 有效、isEmpty() 有效、remove() 有效。测试remove() 假定add() 有效。对于这种情况,您可以使用JExample,这是一个单元测试框架,您可以使用它“链接”测试。

      【讨论】:

        【解决方案3】:

        在任何地方复制代码都是“不好的”。这段代码是出于某种原因重复还是只是为了方便。如果你有理由想要在两者中使用相同的数据并以相同的方式添加它,那么一个小小的“设置”方法是有意义的。

        【讨论】:

          【解决方案4】:

          单元测试代码是生产代码,因此如上面的答案所述,所有代码重复都应避免。

          我通常做的是要么使用@Before 方法进行所有变量初始化,要么使用可以在多个单元测试/项目之间共享的TestUtility 类。

          【讨论】:

            【解决方案5】:

            没有问号的代码重复总是不好的。 为避免在您的情况下发生这种情况,请编写可重用的测试场景(实现该场景并接受参数的私有方法),然后从带有特定参数的 @Test 注释的方法中调用它。

            @Test
            public void shouldRemoveAllDrivingRecords() {
                theTest(0);
            } 
            
            @Test
            public void shouldSumTheDistanceDriven() {
                theTest(0.1);
            } 
            

            如果需要,您还可以创建测试套件。这允许您运行具有不同参数的测试组。

            【讨论】:

              【解决方案6】:

              如果该类中的所有测试方法都需要该代码,我认为我们应该始终将其提取到 setUp() 方法中,否则应该提取到私有辅助方法中。

              【讨论】:

                【解决方案7】:

                另请参阅 Meszaros 的 XUnit Test Patterns,其中包含关于测试代码复制的部分。

                @Before 是给定片段的路径。

                【讨论】:

                  【解决方案8】:

                  我在 JUnit 中也遵循 DRY 原则!我什至编写助手或构建器类来执行重复任务。一个好的 Junit 方法乍一看应该只包含数据,以便清楚什么测试没有污染如何测试它。

                  【讨论】:

                    【解决方案9】:

                    提取所有常用配置到@before。您也可以使用参数,@Parametrized 或我的项目:zohhak,例如。

                    @Before
                    public void prepareBank() {
                      ...
                    }
                    
                    @TestWith({
                       "25 USD",
                       "38 GBP",
                       "null"
                    })
                    public void testMethod(Money money) {
                       ...
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-11-09
                      • 2013-02-19
                      • 2011-03-18
                      • 2012-01-18
                      • 1970-01-01
                      • 2018-07-20
                      • 1970-01-01
                      相关资源
                      最近更新 更多