【问题标题】:Is there a way to test other assertions inside a test after calling tSQLt.ExpectException?有没有办法在调用 tSQLt.ExpectException 后测试测试中的其他断言?
【发布时间】:2023-03-31 12:47:01
【问题描述】:

使用 tSQLt 1.0.5873.27393,我正在尝试为存储过程编写 tSQLt 测试,该存储过程将捕获在 CATCH 块中的错误记录到日志表中,然后再将错误重新抛出到调用会话。

我可以成功测试使用tSQLt.ExpectException 重新抛出错误消息,但副作用似乎是在调用tSQLt.ExpectException 后无法测试任何其他断言 - 所以我无法测试是否错误已写入日志表。

我能想出的证明问题的最简单的测试是:

CREATE PROC MyTests.[test ExpectException]
AS
BEGIN
    EXEC tSQLt.ExpectException;
    THROW 50001, 'Error message',1

    EXEC tSQLt.AssertEquals 0,1, '0=1'
END
GO

执行时会产生以下(意外)输出:

|No|Test Case Name                  |Dur(ms)|Result |
+--+--------------------------------+-------+-------+
|1 |[MyTests].[test ExpectException]|      3|Success|

使用分析器跟踪,我可以看到AssertEquals 断言从未执行,因为错误被CATCH 块在tSQLt.Private_RunTest 中捕获。

因为 tSQLt 使用 CATCH 来捕获错误,我怀疑如果不对 tSQLt 进行重大重写,就无法解决这个问题 - 但我在这里询问以防其他人找到解决问题的方法。

【问题讨论】:

  • 建议/最佳实践:让您的测试尽可能原子化(一次测试一件事)。我会将这个场景分成两个测试(一个用于错误,一个用于日志记录)。
  • @EduardUta - 如果可以的话,我会这样做,但在这种情况下,这是不可能的;我正在测试的代码路径只有在抛出错误时才会执行,并且错误总是随后会重新抛出。
  • 是的,你可以。一个使用 ExpectException 的测试,另一个使用 TRY...CATCH 方法只查看日志表。
  • @SebastianMeine - 感谢您的澄清

标签: tsqlt


【解决方案1】:

您可以采用这种方法:

在测试中,将对测试存储过程的调用包装在 try/catch 块中。 在 try/catch 块之前,将预期变量设置为 1,将实际变量设置为 0。 在测试捕获块中,检查日志表是否已填充,如果是,则将实际变量翻转为 1。 在 catch 块之后写下你的断言。

CREATE PROC MyTests.[test ExpectException]
AS
    BEGIN
    DECLARE @expected bit = 1;
    DECLARE @actual bit = 0;

    BEGIN TRY
        -- call tested SP, make sure it fails
        CALL SP..;

        -- add safety net, if the SP call doesn't fail then fail the test
        RAISERROR('Fail the test', 16, 1);
    END TRY
    BEGIN CATCH
        -- pseudo code
        IF EXISTS (SELECT 1 FROM log table)
        -> flip @actual to 1
    END CATCH

    EXEC tSQLt.AssertEquals @expected, @actual
END
GO

【讨论】:

    【解决方案2】:

    @Eduard Uta 在我之前到达了那里,但我还是会发布这个。


    我一发布这个消息就突然意识到,显而易见的解决方案是使用自定义的 TRY...CATCH 块,而不是内置的 tSQLt 对象:

    CREATE PROC MyTests.[test custom try catch]
    AS
    BEGIN
        DECLARE @ErrorRaised bit = 0
    
        BEGIN TRY
            THROW 50001, 'Error message',1
        END TRY
        BEGIN CATCH
            SET @ErrorRaised = 1
        END CATCH
    
        EXEC tSQLt.AssertEquals 1,@ErrorRaised, 'Error raised'
    
        EXEC tSQLt.AssertEquals 0,1, '0=1'
    END
    GO
    

    这是一个测试特定错误消息的示例:

    CREATE PROC MyTests.[test custom try catch test message]
    AS
    BEGIN
        DECLARE @ErrorRaised bit = 0
    
        BEGIN TRY
            THROW 50001, 'Error message',1
        END TRY
        BEGIN CATCH
            IF ERROR_MESSAGE() = 'Error message'
                SET @ErrorRaised = 1
            ELSE
                THROW
        END CATCH
    
        EXEC tSQLt.AssertEquals 1,@ErrorRaised, 'Error raised'
    
        EXEC tSQLt.AssertEquals 0,1, '0=1'
    END
    GO
    

    【讨论】:

      【解决方案3】:

      对我来说,在 TRY...CATCH 块中调用被测过程和 tSQLt ExpectException proc 似乎已经成功了。

      CREATE PROC MyTests.[test ExpectException]
      AS
      BEGIN
        BEGIN TRY
          -- Call the proc that raises the error
          EXEC offending_stored_proc
      
          -- Tell tSQLt to expect the exception
          EXEC tSQLt.ExpectException @ExpectedMessage = 'Expected error message', @ExpectedSeverity = NULL, @ExpectedState = NULL;
        END TRY
        BEGIN CATCH
          -- No need to do anything here
        END CATCH
      END;
      

      正如预期的那样,如果过程通过该错误消息引发错误,则测试通过。如果没有引发错误,则测试失败。

      【讨论】:

        猜你喜欢
        • 2016-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-26
        • 1970-01-01
        • 2015-08-09
        相关资源
        最近更新 更多