Тестирование хранимой процедуры, работающей с временной таблицей вызывающего объекта

Я делал все возможное, чтобы следовать мудрости в http://www.sommarskog.se/share_data.html и документацию по tSQLt; стараясь, чтобы мои хранимые процедуры были легкими и относительно простыми, чтобы их было легко тестировать. Итак, я обнаруживаю, что создаю временную таблицу в основной хранимой процедуре, а затем работаю с этой временной таблицей во «вторичных» хранимых процедурах, вызываемых из основной. Это работает довольно хорошо, но оказывается немного неудобным для тестирования.

При изолированном тестировании "вторичной" хранимой процедуры временная таблица уже должна существовать. Похоже, что создание временной таблицы в процедуре [Set Up] не сохраняется в модульных тестах, но создание полной таблицы сохраняется.

Итак, чтобы избежать повторения CREATE TABLE #temp в каждом модульном тесте (с его полным определением столбца), я делаю вариант следующего:

EXEC tSQLt.NewTestClass 'SEtest';
GO

CREATE PROCEDURE [SEtest].[SetUp]
AS
BEGIN
  CREATE TABLE SEtest.temptemplate (col1 int);
END;
GO

CREATE PROCEDURE [SEtest].[test example]
AS
BEGIN
  -- Assemble
  SELECT TOP (0) * INTO #temp FROM SEtest.temptemplate;
  INSERT INTO #temp (col1)
  VALUES (1),(2),(5),(7);

  -- Act
  EXEC dbo.REMOVE_EVEN_NUMBERS;

  -- Assert
  SELECT TOP (0) * INTO #expected FROM #temp;
  INSERT INTO #expected (col1)
  VALUES (1),(5),(7);

  EXEC tSQLt.AssertEqualsTable '#expected', '#temp';
END;
GO

Есть ли лучшие способы согласования tSQLt с обменом данными между хранимыми процедурами через временные таблицы?


person NReilingh    schedule 21.11.2016    source источник
comment
Я обнаруживаю, что создаю временную таблицу в основной хранимой процедуре, а затем работаю с этой временной таблицей во вторичных хранимых процедурах, вызываемых из основной - я избегаю этого шаблона, где это возможно. Как только реализация «просачивается» из хранимой процедуры, ее становится сложнее поддерживать и тестировать. Встроенная табличная функция часто может быть решением   -  person Mitch Wheat    schedule 21.11.2016
comment
Митч, вынужден не согласиться. В этом контексте определение таблицы #temp является частью контракта между sproc и вызывающей стороной. Таким образом, это не усложняет сопровождение процедуры, если у вас есть нужные тесты. Однако я согласен, что это немного уродливо (но иногда T-SQL уродлив).   -  person Sebastian Meine    schedule 21.11.2016
comment
Единственное, что я могу придумать, что может быть улучшением, - это постоянная таблица с ключом процесса. Пока я не возражаю против небольшого падения производительности из-за того, что не нахожусь в tempdb и имею дополнительный объект в базе данных, я, вероятно, могу просто FakeTable в тестах, как обычно.   -  person NReilingh    schedule 21.11.2016


Ответы (1)


На самом деле нет лучшего способа.

Использование таблицы #temp в качестве ссылки на параметр с табличным значением по своей сути уродливо в T-SQL и также приводит к уродству в тестах. Тем не менее, ваши тесты кажутся хорошо продуманными и должны давать то, что вы ищете.

Единственное улучшение вашего шаблона, которое я бы предложил, - это создать таблицу SEtest.temptemplate в тестовой схеме на постоянной основе, а не воссоздавать ее на лету каждый раз при запуске теста.

Использование SELECT ... INTO для создания конкретных тестовых таблиц — это шаблон, который я использую повсеместно в своих тестах. И поскольку вы не можете создавать временные таблицы в подпроцедурах, это единственный доступный нам чистый вариант.

В любом случае, не используйте оператор CREATE TABLE в своих тестах для создания таблицы #temp, так как это станет кошмаром для обслуживания, если схема таблицы когда-либо изменится.


Обновлять:

Есть одна альтернатива, которую вы, возможно, захотите рассмотреть. Поскольку ваша таблица #temp в основном представляет собой параметр с табличным значением, было бы неплохо использовать тип таблицы. Теперь это все еще неуклюже, но повышает удобство сопровождения со всех сторон:

DECLARE @template AS dbo.tabletype;
SELECT * INTO #temptable FROM @template;

Это делает его более читаемым, особенно если имя вашего типа таблицы является выразительным (и оно находится в той же схеме, что и рассматриваемая процедура).

При этом вы можете использовать один и тот же шаблон в любой вызывающей процедуре, а не только в тестах. Это также делает фактический код немного более очевидным/читабельным и сокращает объем работ по обслуживанию, если определение таблицы когда-либо изменится.

person Sebastian Meine    schedule 21.11.2016
comment
Обновлено, чтобы добавить дополнительную идею, которая делает код немного более очевидным. - person Sebastian Meine; 22.11.2016