Модульные тесты SQL Server: можно ли создавать временные таблицы в сценарии предварительного тестирования и использовать их в основном тесте?

Я новичок в SQL, пытаюсь создать модульные тесты для хранимых процедур в устаревшей базе данных. Хранимые процедуры извлекают входные данные из временных таблиц, что, по-видимому, упрощает их тестирование. Я хотел бы создать и заполнить эти таблицы в процедуре настройки тестовой системы, запустить хранимую процедуру и затем оценить результаты.

Я настроил свою тестовую среду с помощью Visual Studio 2013 с проектом модульного тестирования SQL Server, как показано в этот пост.

Мой Pre-test выглядит довольно скучно:

CREATE TABLE #foo(
/* fields */)

/* Populate temp table here */

Затем в теле Test я вызываю хранимую процедуру, которая зависит от таблицы #foo:

DECLARE @RC AS INT;
SELECT @RC = 0;
EXECUTE @RC = [dbo].[MyStoredProcedure] ;
SELECT @RC AS RC;

Но когда я запускаю тест, я получаю следующую ошибку:

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'.

На самом деле кажется, что я даже не могу создать переменную в Pre-Test и получить к ней доступ из основной части теста.

Каков «правильный» способ заполнения временной таблицы? Не следует ли использовать область Pre-test для создания временных таблиц?


person ThoughtProcess    schedule 10.12.2013    source источник


Ответы (2)


Проблема здесь в том, что по умолчанию сценарии до и после тестирования выполняются с использованием другого подключения (PrivilegedContext) к тестовому сценарию (ExecutionContext). Вы используете локальную временную таблицу, и область ее действия находится только в пределах текущего соединения. Следовательно, тест не может получить доступ к таблице, поскольку она недоступна в области соединения. Здесь есть два возможных решения:

  1. Используйте глобальную временную таблицу (##foo вместо #foo). Это доступно для любого подключения, поэтому вы можете получить к нему доступ как из контекста Privileged, так и из контекста выполнения. Преимущество в том, что вам не нужно менять свой тестовый код, а недостатком является то, что вы можете не захотеть изменять производственный код только для того, чтобы ваш тест заработал.

  2. Измените соединение, используемое для выполнения тестового или предварительного тестового действия. Это требует редактирования кода C#/VB, который создает разработчик модульных тестов. Если щелкнуть правой кнопкой мыши свой тестовый класс в обозревателе решений и выбрать «Просмотр кода», вы увидите содержимое тестового метода. Вы должны иметь возможность изменить строку «preTestResults», чтобы использовать ExecutionContext. См. пример ниже (в данном случае тест назывался «dbo_Procedure1Test»).

    [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);
        }
    }
    
person Kevin Cunnane    schedule 11.12.2013
comment
Спасибо, Кевин, отличное объяснение и предложение! - person ThoughtProcess; 12.12.2013
comment
Стоит отметить, что четвертый параметр TestService.Execute представляет собой массив DbParameters. Это не решает вопрос OP, но, по-видимому, позволяет вам предоставить единый набор переменных для сценариев предварительного, тестового и посттестового тестирования, независимо от того, в каком контексте они выполняются. Другие люди, наткнувшиеся на этот вопрос, могут быть заинтересованы в этой возможности. Модульное тестирование SSDT настолько ущербно... - person Seth Flowers; 27.04.2016

введите здесь описание изображения

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

person Dorothy Hawley    schedule 01.05.2018