Sql server SQL Server单元测试:可以在";中创建临时表;“预测试”;编写脚本并在主测试中使用它们?

Sql server SQL Server单元测试:可以在";中创建临时表;“预测试”;编写脚本并在主测试中使用它们?,sql-server,tdd,sql-server-data-tools,Sql Server,Tdd,Sql Server Data Tools,我是一名SQL新手,试图为遗留数据库中的存储过程创建单元测试。存储过程从临时表中检索输入数据,这似乎使测试它们变得容易。我想在测试线束设置例程中创建并填充这些表,运行存储过程,然后评估结果 我使用Visual Studio 2013和SQL Server单元测试项目设置了测试环境,如中所示 我的预测试看起来很无聊: CREATE TABLE #foo( /* fields */) /* Populate temp table here */ 然后在Test主体中,我调用存储过程,它取决于表#

我是一名SQL新手,试图为遗留数据库中的存储过程创建单元测试。存储过程从临时表中检索输入数据,这似乎使测试它们变得容易。我想在测试线束设置例程中创建并填充这些表,运行存储过程,然后评估结果

我使用Visual Studio 2013和SQL Server单元测试项目设置了测试环境,如中所示

我的
预测试
看起来很无聊:

CREATE TABLE #foo(
/* fields */)

/* Populate temp table here */
然后在
Test
主体中,我调用存储过程,它取决于表#foo:

但是当我运行测试时,我得到以下错误:

Sql Error: 'Invalid object name '#foo'.' (Severity 16, State 0)

Test method DatabaseTestProj.TestSpike.dbo_SomeStoredPocTest threw exception: 
System.Data.SqlClient.SqlException: Invalid object name '#foo'.
事实上,我甚至不能在预测试中创建一个变量并从测试的主要部分访问它


填充临时表的“正确”方法是什么?是否不应使用
预测试
区域来创建临时表?

这里的问题是,默认情况下,预测试脚本和后测试脚本使用与测试脚本(ExecutionContext)不同的连接(PrivilegedContext)执行。您正在使用本地临时表,其范围仅在当前连接中。因此,测试无法访问该表,因为该表在其连接范围内不可用。这里有两种可能的解决方案:

  • 使用全局临时表(##foo而不是#foo)。这可用于任何连接,因此您可以从特权上下文和执行上下文访问它。好处是您不需要更改测试代码,缺点是您可能不想仅仅为了让测试工作而更改生产代码

  • 更改用于执行测试操作或测试前操作的连接。这需要编辑单元测试设计器创建的C#/VB代码。如果在解决方案资源管理器中右键单击测试类并选择“查看代码”,则可以看到测试方法的内容。您应该能够更改“preTestResults”行以使用ExecutionContext。参见下面的示例(在这种情况下,测试名为“dbo_程序测试”)


  • 这是我制作的一个小图表,可以帮助我直观地看到类的不同部分在哪里使用,以及它们在设计器中的显示位置。

    谢谢Kevin,非常好的解释和建议!值得一提的是TestService.Execute的第4个参数是一个DbParameters数组。这并不能解决OP的问题,但它可能允许您为预测试、测试和测试后脚本提供一组变量,而不管它们在哪个上下文下执行。在这个问题上结结巴巴的其他人可能对这种可能性感兴趣。SSDT单元测试是如此残废。。。
    Sql Error: 'Invalid object name '#foo'.' (Severity 16, State 0)
    
    Test method DatabaseTestProj.TestSpike.dbo_SomeStoredPocTest threw exception: 
    System.Data.SqlClient.SqlException: Invalid object name '#foo'.
    
    [TestMethod()]
    public void dbo_Procedure1Test()
    {
        SqlDatabaseTestActions testActions = this.dbo_Procedure1TestData;
        // Execute the pre-test script
        // 
        System.Diagnostics.Trace.WriteLineIf((testActions.PretestAction != null), "Executing pre-test script...");
    
        // Original code: uses the "PrivilegedContext" for the connection.
        //SqlExecutionResult[] pretestResults = TestService.Execute(this.PrivilegedContext, this.PrivilegedContext, testActions.PretestAction);
    
        // New code: uses the same "ExecutionContext" for the connection that the test section uses
        SqlExecutionResult[] pretestResults = TestService.Execute(this.ExecutionContext, this.PrivilegedContext, testActions.PretestAction);
    
        try
        {
            // Execute the test script
            // 
            System.Diagnostics.Trace.WriteLineIf((testActions.TestAction != null), "Executing test script...");
    
            // The test action uses an ExecutionContext, which is useful if you want to limit the permissions
            // to what an actual caller of the stored procedure would have, but do setup/teardown of test data using
            // a more privileged context. In this case you don't want that, so use the same context for both pre-test and the test itself
            SqlExecutionResult[] testResults = TestService.Execute(this.ExecutionContext, this.PrivilegedContext, testActions.TestAction);
        }
        finally
        {
            // Execute the post-test script
            // 
            System.Diagnostics.Trace.WriteLineIf((testActions.PosttestAction != null), "Executing post-test script...");
            SqlExecutionResult[] posttestResults = TestService.Execute(this.PrivilegedContext, this.PrivilegedContext, testActions.PosttestAction);
        }
    }