2016-11-21 38 views
0

我一直在尽我所能去遵循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存储过程之间的数据通过临时表?

+0

“我发现自己在主存储过程中创建临时表,然后在从主存储过程调用的”辅助“存储过程中在该临时表上进行操作” - 我尽可能避免使用该模式。一旦存储过程执行“泄漏”,维护和测试就变得更加困难。一个内联表值函数通常可以解决方案 –

+0

米奇,我不得不不同意。在这种情况下,#temp表的定义是sproc和调用者之间合同的一部分。因此,如果你有适当的测试,它不会使程序难以维护。不过,我同意,它有点难看(但有时候T-SQL很丑)。 –

+0

我能想出的唯一可能是一个改进将是一个过程键,永久表。只要我不介意不驻留在tempdb中的轻微性能问题,并且在数据库中有一个额外的对象,我可能就像往常一样在测试中伪造FakeTable。 – NReilingh

回答

2

真的没有更好的办法。

使用#temp表作为表值参数引用在T-SQL中本质上是丑陋的,并且也会导致测试中的丑陋。但是,您的测试看起来很周到,应该提供您正在寻找的内容。

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

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

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


更新:

还有就是你可能要考虑一个替代方案。由于#temp表基本上是一个表值参数,所以使用表类型不是一个坏主意。现在,这仍然是笨拙,但它所有的两端增加可维护性:

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

这使得一个更清晰一点可读性,特别是如果你的表类型的名称是表现(这是在同一个模式作为有问题的程序)。

有了这个,你可以在任何调用过程中使用相同的模式,而不仅仅是在测试中。这也使得实际的代码更加明显/可读,并且如果表格定义应该改变,它会减少维护工作。

+0

更新后添加了一个让代码更加明显的额外想法。 –