测试对调用者的临时文件进行操作的存储过程 table

Testing a stored procedure that operates on a caller's temp table

我一直在尽最大努力遵循 http://www.sommarskog.se/share_data.html 和 tSQLt 文档中的智慧;试图让我的存储过程保持轻便和相对简单,以便它们很容易 testable。因此,我发现自己在主存储过程中创建了一个临时 table,然后在从主存储过程调用的 "secondary" 存储过程中对该临时 table 进行操作。这工作得很好,但事实证明测试起来有点尴尬。

单独测试 "secondary" 存储过程时,临时文件 table 必须已经存在。看起来在 [Set Up] 过程中创建临时 table 不会持续到单元测试,但创建完整的 table 会。

因此,为了避免在每个单元测试(及其完整的列定义)中重复 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 与通过 temp tables 在存储过程之间共享数据?

实在是没有更好的办法了

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

我建议对您的模式进行的唯一改进是在测试架构中永久创建 SEtest.temptemplate table,而不是在每次测试运行时即时重新创建它。

使用SELECT ... INTO 创建特定于测试的 tables 是我在测试中到处使用的模式。由于您无法在子过程中创建临时 tables,因此这是我们唯一的干净选项。

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


更新:

您可能要考虑另一种选择。由于您的#temp table 基本上是一个 table 值参数,因此使用 table 类型并不是一个坏主意。现在,这仍然很笨拙,但它提高了各方面的可维护性:

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

这使得可读性更清晰一些,特别是如果您的 table 类型的名称具有表现力(并且它与所讨论的过程处于相同的架构中)。

有了这个,您可以在任何调用过程中使用相同的模式,而不仅仅是在测试中。这也使实际代码多了一点 obvious/readable,如果 table 定义发生变化,它会减少维护工作。