How to ROLLBACK a transaction when testing using tSQLt

前端 未结 4 1436
离开以前
离开以前 2021-01-12 15:05

I recently was calling a procedure that contained a rasierror in the code. The raiserror was in a try catch block. Also a BEGIN TRAN was in the same try catch block after

4条回答
  •  自闭症患者
    2021-01-12 15:14

    As I'm just reading up on tSQLt this was one of the first questions that came to mind when I've learned each test ran in a transactions. As some of my stored procedures do start transaction, some even use nested transactions, this can become challenging. What I've learned about nested transactions, if you apply the following rules you can keep your code clean of constant error checking and still handle errors gracefully.

    • Always use a TRY/CATCH block when opening a transactions
    • Always commit the transactions unless an error was raised
    • Always rollback the transaction when an error is raised unless @@TRANCOUNT = 0
    • Always reraise the error unless you're absolutely sure there was no transaction open at the start of the stored procedure.

    Keeping those rules in mind here is an example of a proc implementation and test code to test it.

    ALTER PROC testProc
        @IshouldFail BIT
    AS
    BEGIN TRY
        BEGIN TRAN
    
        IF @IshouldFail = 1
            RAISERROR('failure', 16, 1);
    
        COMMIT
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK;
    
        -- Do some exception handling
    
        -- You'll need to reraise the error to prevent exceptions about inconsistent 
        -- @@TRANCOUNT before / after execution of the stored proc.
        RAISERROR('failure', 16, 1);
    END CATCH
    GO
    
    
    --EXEC tSQLt.NewTestClass 'tSQLt.experiments';
    --GO
    ALTER PROCEDURE [tSQLt.experiments].[test testProc nested transaction fails]
    AS
    BEGIN
        --Assemble
        DECLARE @CatchWasHit CHAR(1) = 'N';
    
        --Act
        BEGIN TRY
            EXEC dbo.testProc 1
        END TRY
        BEGIN CATCH 
            IF @@TRANCOUNT = 0
                BEGIN TRAN --reopen an transaction
            SET @CatchWasHit = 'Y';
        END CATCH
    
        --Assert
        EXEC tSQLt.AssertEqualsString @Expected = N'Y', @Actual = @CatchWasHit, @Message = N'Exception was expected'
    
    END;
    GO
    
    ALTER PROCEDURE [tSQLt.experiments].[test testProc nested transaction succeeds]
    AS
    BEGIN
        --Act
        EXEC dbo.testProc 0
    
    END;
    GO
    
    EXEC tSQLt.Run @TestName = N'tSQLt.experiments'
    

提交回复
热议问题