Using tSQLt 1.0.5873.27393, I'm trying to write a tSQLt test for a stored procedure that records errors trapped in a CATCH
block to a log table before re-throwing the error to the calling session.
I can successfully test that the error message is re-thrown using tSQLt.ExpectException
, but a side effect seems to be that it's not possible to test any other assertions after calling tSQLt.ExpectException
- so I am unable to test whether the error has been written to the log table.
The simplest test that I can come up with which demonstrates the problem is:
CREATE PROC MyTests.[test ExpectException]
AS
BEGIN
EXEC tSQLt.ExpectException;
THROW 50001, 'Error message',1
EXEC tSQLt.AssertEquals 0,1, '0=1'
END
GO
which produces the following (unexpected) output when executed:
|No|Test Case Name |Dur(ms)|Result |
+--+--------------------------------+-------+-------+
|1 |[MyTests].[test ExpectException]| 3|Success|
Using a profiler trace, I can see that the AssertEquals
assertion is never executed, because the error is trapped by a CATCH
block inside tSQLt.Private_RunTest
.
Because tSQLt uses CATCH
to trap errors, I suspect that there's no solution to this problem without a major rewrite of tSQLt - but I ask here just in case others have found a way around the issue.
You could follow this approach:
In the test, wrap your call to the tested stored procedure in a try/catch block. Before the try/catch block, set up an expected variable to 1 and actual to 0. In the test catch block, check if the log table got populated and if yes then flip the actual variable to 1. Write your assertion AFTER the catch block.
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