-1

我正在尝试测试一个使用动态 sql 的存储过程,如下所示:

DECLARE @Sql NVARCHAR(MAX)

-- create @Sql

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

无论我做什么,我都没有通过测试。我在用

EXEC tSQLt.FakeTable

伪造底层数据库的数据。tsqlt 不能与动态 sql 一起工作,这是一个众所周知的事实吗?

PS:

更多代码:

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
4

1 回答 1

2

正如其他人所评论的那样,动态 SQL 确实适用于 tSQLt。如果没有您遇到问题的代码/测试,就很难确定您的问题可能出在哪里。

为了帮助您并帮助您恢复对 tSQLt 的信心,这里有一个使用动态 SQL 的 SP 示例,以及调用它的测试和假表,以对过程进行单元测试:

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

这个简单的示例应该有助于让您确信 tSQLt 本身能够很好地使用动态 SQL - 也许还有另一个导致您出现问题的依赖项?如果(正如其他人所说)您可以发布您的问题的(可运行)示例,我们可以帮助您找出导致您这种痛苦的原因。

于 2014-05-12T20:00:19.040 回答