代码之家  ›  专栏  ›  技术社区  ›  trendl

引发特殊类型的异常以终止单元测试

  •  2
  • trendl  · 技术社区  · 15 年前

    假设我想编写一个单元测试来测试一个方法中实现的特定功能。如果我想完全执行这个方法,我必须做一些额外的设置工作(模拟对象期望等)。我不这样做,而是使用以下方法:
    -我设置了对验证感兴趣的期望值,然后使测试方法抛出一个特殊的异常类型(例如TerminateStexception)。
    -在单元测试的更深处,我捕获异常并验证模拟对象期望。

    它很好用,但我不确定它是否是好的做法。我不经常这样做,只是在一些情况下,它可以节省我的时间和精力。作为反对使用这一方法的一个论据,我想到的一点是抛出异常需要很长时间,因此测试的执行速度要比使用不同的方法慢。

    编辑:
    只是澄清一下,我没有修改SUT代码。我要做的是提供一个模拟对象或重写sut类,以便sut在我感兴趣的部分执行后退出执行。

        private class TestCalculationService : CalculationService
        {
            public bool ValidateForSyncCalled;
    
            protected override void ValidateForSyncCall()
            {
                ValidateForSyncCalled = true;
                throw new ExceptionToTerminateTest();
            }                
        }  
    
    
        [TestMethod]
        public void CalculationService_Calculate_Sync_Calls_ValidateForSyncCall()
        {
            InitializeMocks();
            TestCalculationService calculationService = new TestCalculationService();
            calculationService.MessageInstanceFactory = _mockMessageInstanceFactory;
    
            try
            {
                calculationService.Calculate( null);
                Assert.Fail("Exception should have been thrown");
            }
            catch (ExceptionToTerminateTest)
            {
                //ok
            }
    
            Assert.IsTrue(calculationService.ValidateForSyncCalled );
        }
    
    3 回复  |  直到 15 年前
        1
  •  3
  •   tvanfosson    15 年前

    如果您可以单独成功地测试一个方法的部分,那么该部分方法本身就应该是一个较小方法的候选者。我更喜欢重构较小的方法,而不是检测模拟对象以在执行过程中部分中止方法,或者更糟的是,修改实际代码以了解测试。

        2
  •  0
  •   Carl Manaster    15 年前

    我不担心对速度的影响-这是最小的。

    但我认为这不是一个好的练习。主要是因为如果您专门添加客户机代码以方便测试(而不是将类设计为可测试的类),那么这始终是一个坏迹象。您正在测试的方法是否可能做得太多?如果您有一个很好的理由将该方法留在测试中,那么也许该代码块本身就是一个方法?

    我还想知道如何在运行时避免这个异常。如果您开始使用这样的代码:

    if (IsTesting)
    {
        throw new TerminateTestException();
    }
    

    然后就可以证明正在测试的代码与实际运行的代码不同。在这种情况下,你真的在测试什么吗?

    最后一个想法是:我假设您正在为至少一个测试用例(贯穿始终的用例,或者测试用例)设置所有模拟,以确保异常 不是 不该扔的时候扔)。如果您正在这样做,那么可能您在测试类本身中缺少了一些重构的可能性。您不需要为每个测试单独建立模拟对象。

        3
  •  0
  •   Gutzofter    15 年前

    在我看来,您最好将这段代码提取到自己的方法中并进行测试。它叫 发芽法 .