7

最近、コードに rasierror を含むプロシージャを呼び出していました。レイザーエラーは try catch ブロックにありました。また、BEGIN TRAN は、raiserrr の後の同じ try catch ブロックにありました。Catch ブロックは、トランザクションでエラーが発生した場合にトランザクションを ROLLBACK するように設計されています。これを行う方法は、@@TRANCOUNT が 0 より大きいかどうかを確認することです。トランザクションが開始され、ロールバックする必要があることがわかっています。tSQLt でテストする場合、@@TRANCOUNT は常に >0 であるため、CATCH ブロックにヒットすると ROLLBACK が実行され、tSQLt は失敗します (tSQLt がトランザクションで実行されているため)。エラーが発生し、CATCH ブロックが実行されると、tSQLt は常にテストに失敗します。レイザーエラーの正しい処理をテストする方法がありません。トランザクションをロールバックする可能性のあるテスト ケースをどのように作成しますか?

4

4 に答える 4

8

あなたが述べたように、tSQLtはそれ自身のトランザクションですべてのテストを実行します。何が起こっているかを追跡することは、テストが終了したときにまだ開いている同じトランザクションに依存しています。SQL Serverはネストされたトランザクションをサポートしていないため、現在のテスト用にフレームワークに格納されているステータス情報を含め、プロシージャはすべてをロールバックします。その時点で、tSQLtは本当に悪いことが起こったとしか想定できません。したがって、テストにエラーのマークが付けられます。

SQL Server自体は、開いているトランザクション内でプロシージャが呼び出された場合にエラーをスローすることにより、プロシージャ内でのロールバックを阻止します。この状況に対処する方法といくつかの追加情報については、手順をロールバックする方法についての私のブログ投稿を確認してください。

于 2012-01-23T20:08:20.547 に答える
3

tSQLt について読んでいるときに、これは、各テストがトランザクションで実行されることを知ったときに頭に浮かんだ最初の質問の 1 つです。私のストアド プロシージャの中にはトランザクションを開始するものもあれば、ネストされたトランザクションを使用するものもあるため、これは困難になる可能性があります。ネストされたトランザクションについて私が学んだことは、次のルールを適用すると、コードを一定のエラー チェックから解放し、エラーを適切に処理することができるということです。

  • トランザクションを開くときは常に TRY/CATCH ブロックを使用する
  • エラーが発生しない限り、常にトランザクションをコミットする
  • @@TRANCOUNT = 0 でない限り、エラーが発生した場合は常にトランザクションをロールバックします
  • ストアド プロシージャの開始時にトランザクションが開かれていないことが確実でない限り、常にエラーを発生させます。

ここでは、これらのルールを念頭に置いて、proc の実装とそれをテストするためのテスト コードの例を示します。

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'
于 2015-02-28T23:19:20.580 に答える
0

BEGIN TRYの後にブロックを使用することをお勧めしますBEGIN TRANSACTION。同様の問題が発生したときにこれを行いました。CATCHブロックでチェックしたので、これはより論理的IF @@TRANCOUNT > 0 ROLLBACKです。の前に別のエラーが発生した場合、この条件をチェックする必要はありませんBEGIN TRANSACTION。この場合、RAISERROR機能をテストできます。

于 2014-03-19T13:22:53.067 に答える