-1

次のような動的SQLを使用するsprocをテストしようとしています:

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 に答える