Запуск tsqlt assert внутри курсора
Я пишу tsqlt против proc, который может быть запущен для различных значений параметров. Сначала я создал процедуру, которая заполняет поддельные таблицы, а затем 1 тест tsqlt на каждое возможное значение (в итоге было 35 тестов, и каждый из них работал).
То, что я хотел бы сделать, это сократить их до 1 теста (поскольку все они действительно тестируют одну и ту же функциональность - только для разных значений). Я думал, что смогу сделать это с помощью курсора следующим образом:
---- Declare Sproc Variables
DECLARE @ReviewId INT;
DECLARE @SourceId INT = 1;
CREATE TABLE #Present
(
SubmissionReviewId INT ,
username VARCHAR(50)
);
CREATE TABLE #Expected
(
SubmissionReviewId INT ,
username VARCHAR(50)
);
--Create Cursor to loop through each active value
DECLARE review_id CURSOR
FOR
SELECT ReviewId
FROM reftype.Rev
WHERE IsActive = 1;
OPEN review_id;
FETCH NEXT FROM review_id
INTO @ReviewId;
WHILE @@FETCH_STATUS = 0
BEGIN
--Setup Fake Data according to the specified test condition
EXEC ut_DataSetupProc @ReviewId = @ReviewId;
-- Run set cutover Sproc
EXEC Procbeing Tested @ReviewId = @ReviewId,
@SourceId = 1, @Username = 'blah';
-- Confirm appropriate review is present in Submission Review Active
DELETE FROM #Present;
DELETE FROM #Expected;
INSERT INTO #Present
SELECT SubmissionReviewId ,
LastModifiedBy
FROM review.SubmissionReviewActive
ORDER BY SubmissionReviewId ,
LastModifiedBy;
/**********************Create table holding expected values***************************/
INSERT INTO #Expected
--This confirms active reviews that belong to other sections/sources remain unaffected
SELECT SubmissionReviewId ,
LastModifiedBy
FROM review.SubmissionReviewActive
WHERE ( ReviewId != @ReviewId )
OR ( SourceId != @SourceId )
UNION
SELECT sra.SubmissionReviewId ,
sra.LastModifiedBy
FROM review.SubmissionReviewActive sra
JOIN review.SubmissionReviewFutureActive srfa ON srfa.IssuerId = sra.IssuerId
AND srfa.ReviewId = sra.ReviewId
AND srfa.Version < sra.Version
WHERE sra.ReviewId = @ReviewId
AND sra.SourceId = @SourceId
UNION
SELECT srfa.SubmissionReviewId ,
'jmarina' AS LastModifiedBy
FROM review.SubmissionReviewFutureActive srfa
JOIN review.SubmissionReviewActive sra ON srfa.IssuerId = sra.IssuerId
AND srfa.ReviewId = sra.ReviewId
AND srfa.Version > sra.Version
WHERE sra.ReviewId = @ReviewId
AND srfa.SourceId = @SourceId
UNION
SELECT srfa.SubmissionReviewId ,
'blah' AS LastModifiedBy
FROM review.SubmissionReviewFutureActive srfa
WHERE srfa.ReviewId = @ReviewId
AND srfa.SourceId = @SourceId
AND srfa.IssuerId NOT IN (
SELECT IssuerId
FROM review.SubmissionReviewActive
WHERE ReviewId = @ReviewId
AND SourceId = @SourceId )
UNION
SELECT sra.SubmissionReviewId ,
sra.LastModifiedBy
FROM review.SubmissionReviewActive sra
WHERE sra.ReviewId = @ReviewId
AND sra.SourceId = @SourceId
AND IssuerId NOT IN (
SELECT IssuerId
FROM review.SubmissionReviewFutureActive
WHERE ReviewId = @ReviewId
AND SourceId = @SourceId )
ORDER BY SubmissionReviewId ,
LastModifiedBy;
/*************************************************************/
EXEC tSQLt.AssertEqualsTable @Expected = '#Expected',
@Actual = '#Present', @Message = N'', -- nvarchar(max)
@FailMsg = N'Active Status is not a match'; -- nvarchar(max)
FETCH NEXT FROM review_id
INTO @ReviewId;
END;
CLOSE review_id;
DEALLOCATE review_id;
DROP TABLE #Expected;
DROP TABLE #Present;
END;
Тем не менее, запуск этого с использованием
EXEC proc name @ReviewId = @ReviewId;
выдает сообщение о том, что тесты не выполнялись Как я могу подать в суд на курсор, чтобы уменьшить количество тестов? Или есть другой подход, который я должен рассмотреть?
2 ответа
В конце концов, я достиг конечной цели за пару шагов: 1. Переместить оператор assert за пределы курсора 2. Создать временную таблицу cased с записями pass/fail
INSERT INTO #ActualAssert
SELECT p.SubmissionReviewId,e.SubmissionReviewId,
CASE WHEN ( e.SubmissionReviewId IS NULL
OR p.SubmissionReviewId IS NULL
) THEN 'Fail'
ELSE 'Pass'
END
FROM @Present p
LEFT JOIN @Expected e ON e.SubmissionReviewId = p.SubmissionReviewId
UNION
SELECT p.SubmissionReviewId,e.SubmissionReviewId ,
CASE WHEN ( e.SubmissionReviewId IS NULL
OR p.SubmissionReviewId IS NULL
) THEN 'Fail'
ELSE 'Pass'
END
FROM @Present p
RIGHT JOIN @Expected e ON e.SubmissionReviewId = p.SubmissionReviewId;
3. За пределами курсора я установил новый параметр, который принимает любые ошибки, если они существуют, или "проходит", если они не существуют.
SET @Result = ( SELECT DISTINCT TOP 1
TestStatus
FROM #ActualAssert
ORDER BY TestStatus ASC
);
4. Затем я изменил assert, чтобы он не выполнялся, если @result отличается от 'Pass'
EXEC tSQLt.AssertEqualsString @Expected = N'Pass', -- nvarchar(max)
@Actual = @Result, @Message = N''; -- nvarchar(max)
** Примечание: я заменяю предыдущие существующие и ожидаемые временные таблицы на таблицы переменных
Я бы посоветовал вам написать что-то, что называется параметризованным тестом.
tSQLt (пока) не имеет встроенной поддержки для этого, но есть простой обходной путь:
Вы начинаете с написания одного из ваших тестов в обычном режиме. Но вместо того, чтобы жестко задавать соответствующие значения, вы устанавливаете их как параметры процедуры. (Для наборов данных вы можете использовать параметры таблицы.)
Вы также называете эту процедуру именем, которое не начинается с "test" (но находится в той же схеме).
Затем вы пишете один реальный тест для каждого конкретного случая, каждый из которых состоит из одной строки: выполнение вашей параметризованной процедуры.
Это приведет к тестам, которые намного легче понять, чем ваш текущий подход. И, кроме того, если один из них выходит из строя, вы сразу знаете, какой.
Как примечание: вы всегда хотите жестко закодировать ожидаемые результаты. Ваш текущий код очень сложный. Вы хотите свести к минимуму вещи, которые могут пойти не так в самом тесте. Действительно, вашей целью должны быть тесты, которые можно понять одним взглядом.