测试在调用者的临时表上运行的存储过程

时间:2016-11-21 00:18:15

标签: sql-server unit-testing stored-procedures tsqlt

我一直在尽力遵循http://www.sommarskog.se/share_data.html和tSQLt文档中的智慧;试图保持我的存储过程轻,相对不复杂,以便它们易于测试。所以,我发现自己在主存储过程中创建临时表,然后在" secondary"中运行该临时表。从主要存储过程调用存储过程。这很有效,但事实证明它有点尴尬。

测试"中学"存储过程处于隔离状态,临时表必须已经存在。看起来在[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与通过临时表在存储过程之间共享数据?

1 个答案:

答案 0 :(得分:2)

真的没有更好的方法。

使用#temp表作为表值参数引用在T-SQL中本质上是丑陋的,并且在测试中也会导致丑陋。但是,您的测试似乎已经过深思熟虑,应该能够满足您的需求。

我建议的模式的唯一改进是永久地在测试模式中创建SEtest.temptemplate表,而不是每次测试运行时动态地重新创建它。

使用SELECT ... INTO创建测试特定表是我在测试中使用的模式。因为你不能在子程序中创建临时表,所以它是我们唯一的清洁选项。

无论哪种方式,都不要在测试中使用CREATE TABLE语句创建#temp表,因为如果表模式发生变化,这将成为维护的噩梦。

更新

您可能需要考虑一种替代方案。由于您的#temp表基本上是一个表值参数,因此使用表类型并不是一个坏主意。现在,这仍然是笨拙的,但它增加了所有目的的可维护性:

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

这使得可读性更加清晰,特别是如果表类型的名称具有表现力(并且它与所讨论的过程位于相同的模式中)。

通过这种方式,您可以在任何调用过程中使用相同的模式,而不仅仅是在测试中。这也使得实际代码更加明显/可读,如果表定义发生变化,它会减少维护工作。