tSQLt, триггеры и тестирование

Я пытался обернуть это вокруг себя, но не могу заставить его работать, поэтому я привожу небольшой тестовый пример, и, надеюсь, кто-нибудь сможет мне это объяснить:

Сначала небольшая тестовая база данных:

CREATE DATABASE test;
USE test;
CREATE TABLE testA (nr INT)
GO

CREATE TRIGGER triggerTestA
ON testA
FOR INSERT AS BEGIN
  SET NOCOUNT ON;
  IF EXISTS (SELECT nr FROM Inserted WHERE nr > 10)
    RAISERROR('Too high number!', 16, 1);
END;

А вот тест tSQL, чтобы проверить поведение:

ALTER PROCEDURE [mytests].[test1] AS
BEGIN
  EXEC tSQLt.FakeTable @TableName = N'testA'
  EXEC tSQLt.ApplyTrigger  
    @TableName = N'testA', 
    @TriggerName ='triggerTestA'
  EXEC tSQLt.ExpectException
  INSERT INTO dbo.testA VALUES (12)
END;

Этот тест будет работать нормально - но триггер не делает то, что я хочу: запретить пользователю вводить значения> 10. Эта версия триггера делает то, что я хочу:

CREATE TRIGGER triggerTestA
ON testA FOR INSERT AS BEGIN
  SET NOCOUNT ON;
  BEGIN TRANSACTION;
  BEGIN TRY
    IF EXISTS (SELECT nr FROM Inserted WHERE nr > 10)
      RAISERROR('Too high number!', 16, 1);
    COMMIT TRANSACTION;
  END TRY
  BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW;
  END CATCH;
END;

Но теперь тест не пройден, заявив, A) есть ошибка (что и ожидалось!), И B), что нет BEGIN TRANSACTION, чтобы соответствовать ROLLBACK TRANSACTION. Я предполагаю, что эта последняя ошибка связана с транзакцией tSQL t, и что мой триггер как-то мешает этому, но это точно не то, что я ожидаю.

Может ли кто-нибудь объяснить, и, возможно, помочь мне сделать это правильно?

2 ответа

В настоящее время tSQLt ограничен для запуска тестов в своей собственной транзакции и, как вы видели, реагирует, как вы уже не приветствовали, когда вы возитесь с его транзакцией.

Итак, чтобы этот тест работал, вам нужно пропустить откат внутри теста, но не снаружи.

Я предлагаю этот подход:

  1. Удалите все операторы обработки транзакций из триггера. В любом случае вам не нужно начинать транзакцию, поскольку триггеры всегда выполняются внутри нее.
  2. Если вы обнаружите строку с нарушением, вызовите процедуру, которая выполняет откат и ошибку
  3. Шпион, что процедура для вашего теста

Чтобы протестировать саму процедуру, вы можете использовать tSQLt.NewConnection

Как насчет добавления транзакций таким образом, чтобы разрешить вложение? Ниже я создаю транзакцию, только если я еще не участвую в транзакции.

      CREATE <PROCEDURE or TRIGGER>
BEGIN

DECLARE @TranName VARCHAR(32),
    @IsTranCreatedByThis BIT = 0;
SET @TranName = REPLACE((CAST(NEWID() AS VARCHAR(36))),'-','');

IF @@TRANCOUNT = 0
BEGIN
    SET @IsTranCreatedByThis = 1;
    BEGIN TRAN
END

SAVE TRAN @TranName

BEGIN TRY

     -- Your transaction statement here
                             
    IF (@IsTranCreatedByThis = 1)
    BEGIN
        COMMIT TRAN
    END
END TRY 
BEGIN CATCH     
    IF @@TRANCOUNT > 0
    BEGIN
        IF (@IsTranCreatedByThis = 1)
        BEGIN
            ROLLBACK TRAN
        END
        ELSE
        BEGIN
            ROLLBACK TRAN @TranName
        END
    END
    THROW;
END CATCH
END
Другие вопросы по тегам