Pregunta

I am trying to test a sproc which uses dynamic sql like this:

DECLARE @Sql NVARCHAR(MAX)

-- create @Sql

EXEC sp_executesql @Sql
,N'@NumberOfRollingMonths INT, @FromDate DATETIME, @ToDate DATETIME'
,@NumberOfRollingMonths = @NumberOfRollingMonths
,@FromDate = @FromDate
,@ToDate = @ToDate

Whatever I do, I do not get the the test to pass. I am using

EXEC tSQLt.FakeTable

to fake the underlying database's data. Is it a known fact that tsqlt does not work with dynamic sql?

PS:

Some more code:

IF OBJECT_ID('TestDetails', 'U') IS NOT NULL
  DROP TABLE TestDetails

CREATE TABLE TestDetails
(
    Year INT,
    Period INT,
    HOURS INT 
)
INSERT INTO TestDetails (Year, Period, HOURS) 
    SELECT 2004, 1, 10000 UNION ALL
    SELECT 2004, 2, 100

IF OBJECT_ID('TestMonthsAndYears', 'U') IS NOT NULL
  DROP TABLE TestMonthsAndYears

CREATE TABLE TestMonthsAndYears
(
    Id INT not null identity(1,1) primary KEY,
    TheMonth INT NOT NULL,
    TheYear INT NOT NULL,
    [Date] DATETIME NOT NULL 
)

DECLARE @FromDate DATETIME
DECLARE @ToDate DATETIME
SET @FromDate = '1900-01-01 00:00:00.000'
SET @ToDate = '2200-01-01 00:00:00.000'

INSERT INTO TestMonthsAndYears 
SELECT 
    TOP (DATEDIFF(MONTH, @FromDate, @ToDate) + 1) 
    [TheMonth] = MONTH(DATEADD(MONTH, number, @FromDate)),
    [TheYear]  = YEAR(DATEADD(MONTH, number, @FromDate)),
    [Date]  = DATEADD(month, DATEDIFF(month, 0, DATEADD(MONTH, number, @FromDate)), 0)
FROM [master].dbo.spt_values 
WHERE [type] = N'P'

IF EXISTS (SELECT * FROM sys . objects WHERE type = 'P' AND name = 'ToBeRemoved' )
DROP PROCEDURE ToBeRemoved
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: 
-- =============================================
CREATE PROCEDURE [dbo].[ToBeRemoved]
    @FromDate DATETIME,
    @ToDate DATETIME,
    @NumberOfRollingMonths INT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Sql NVARCHAR(MAX)
    DECLARE @SumSql NVARCHAR(MAX)

    SET @SumSql = N''
    IF(@NumberOfRollingMonths > 0)
        BEGIN
            SET @NumberOfRollingMonths = @NumberOfRollingMonths * -1;
        END

    SET @SumSql = @SumSql + N' SUM(CAST(D.HOURS AS FLOAT)) '

    SET @Sql = N'
    ;WITH SparseValues AS
    (
        SELECT 
            CAST(CAST(D.YEAR AS VARCHAR(4)) + RIGHT(''0'' + CAST(D.Period AS VARCHAR(2)),2) + ''01'' AS SMALLDATETIME) AS MonthYear,
            ' + @SumSql + ' AS Value
        FROM TestDetails D
        GROUP BY CAST(CAST(D.YEAR AS VARCHAR(4)) + RIGHT(''0'' + CAST(D.Period AS VARCHAR(2)),2) + ''01'' AS SMALLDATETIME) 
    )
    ,CompleteValues AS 
    (
        SELECT 
            MY.[Date], 
            ISNULL(Value,0) AS Value
        FROM TestMonthsAndYears MY
        LEFT JOIN SparseValues SparseValues ON MY.[Date] = SparseValues.MonthYear
        WHERE MY.Date BETWEEN @FromDate AND @ToDate
    )
    SELECT 
        S1.[Date], 
        AVG(S2.Value) AS MovingAverage
    FROM CompleteValues AS S1, CompleteValues AS S2
    WHERE S2.[Date] > DATEADD(m, @NumberOfRollingMonths,S1.[Date]) AND S2.[Date] <= S1.[Date]
    GROUP BY S1.[Date] order by date'

    EXEC sp_executesql @Sql
        ,N'@NumberOfRollingMonths INT, @FromDate DATETIME, @ToDate DATETIME'
        ,@NumberOfRollingMonths = @NumberOfRollingMonths
        ,@FromDate = @FromDate
        ,@ToDate = @ToDate
END


EXEC tSQLt.NewTestClass 'MyTestClass';
GO

CREATE PROCEDURE [MyTestClass].[test very good test]
AS
BEGIN
    -- arrange 
    IF OBJECT_ID('Expected') IS NOT NULL DROP TABLE Expected;
    IF OBJECT_ID('Actual') IS NOT NULL DROP TABLE Actual;

    EXEC tSQLt.FakeTable 'dbo', 'TestDetails';
    INSERT INTO dbo.TestDetails (Year, period, [HOURS]) 
        SELECT 2004, 1, 30 UNION ALL
        SELECT 2004, 2, 10

    CREATE TABLE Expected(Date DATETIME, MovingAverage float)
    CREATE TABLE Actual(Date DATETIME, MovingAverage float)
    INSERT INTO Expected (Date, MovingAverage) 
        SELECT '2004-01-01 00:00:00.000', 30 UNION ALL
        SELECT '2004-02-01 00:00:00.000', 10

    -- act
    DECLARE @FromDate DATETIME SET @FromDate = '2004-01-01 00:00:00.000'
    DECLARE @ToDate DATETIME SET @ToDate = '2004-02-01 00:00:00.000'
    DECLARE @NumberOfRollingMonths INT SET @NumberOfRollingMonths = -1

    INSERT INTO Actual
    EXEC ToBeRemoved @FromDate, @ToDate, @NumberOfRollingMonths

    EXEC tSQLt.AssertEqualsTable 'Expected', 'Actual', 'Actual result table not equal to expected result table.';
END
¿Fue útil?

Solución

As others have commented, Dynamic SQL does work with tSQLt. Without the code / test with which you are experiencing issues, it's difficult to be definitive as to where your problem might lie.

To help you along, and help restore your confidence in tSQLt, here's an example of a SP using dynamic SQL, and a test that calls it, and fake table, to unit test the procedure:

USE tSQLt_Example
GO
--Example table in which we will manipulate data
CREATE TABLE dbo.DynamicDemo (a INT)
GO
INSERT dbo.DynamicDemo (a) VALUES (5) -- This value will be removed by FakeTable
GO
--Example proc which uses Dynamic SQL
CREATE PROC dbo.DynamicAdd (@NoToAdd int) as
DECLARE @s NVARCHAR(MAX)
SET @s = 'update dbo.DynamicDemo set a=a+@NoToAdd'
EXEC sp_executesql @s,N'@NoToAdd int',@NoToAdd = @NoToAdd
GO
--create tSQLt class
exec tSQLt.NewTestClass @ClassName = N'DynamicTest' -- nvarchar(max)
GO
--Create test on proc which uses dynamic SQL
CREATE PROC DynamicTest.[test dynamic sql]
as
--Assemble
EXEC tSQLt.faketable 'dbo.DynamicDemo'
SELECT TOP 0 * into DynamicTest.Expected FROM dbo.DynamicDemo
INSERT dbo.DynamicDemo (a) VALUES (4) --Start position
INSERT DynamicTest.Expected (a) VALUES (7) -- Expected end position
--Act
EXEC dbo.DynamicAdd 3 --call proc under test
--Assert
EXEC tSQLt.AssertEqualsTable @Actual='dbo.DynamicDemo', @Expected = 'DynamicTest.Expected'
GO
--Run Tests
EXEC tSQLt.Run 'DynamicTest'
GO
--Clearup
DROP TABLE dbo.dynamicDemo
DROP PROC dbo.DynamicAdd

This simple example should help to reassure you that tSQLt itself is capable of using dynamic SQL just fine - perhaps there is another dependency which is causing you issues? If (as others have said) you can post a (runable) example of your problem we can help you work out what is causing you this pain.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top