faketable 関数が通常に再割り当てされませんでした。faketable を使用したすべてのテーブルには、単体テストの挿入で使用した値のコンテンツが含まれています。それは多くのテーブルであり、データベースが役に立たなくなりました。この問題、または少なくともその原因の解決にご協力ください。これにより、CI 展開プロセスでこれを使用することに非常に神経質になります。さらに重要なのは、ローカル開発の取り組みです。
5 に答える
テストまたはコードの 1 つが、トランザクションをロールバックできない状態のままにしている可能性があります。これにより、通常、結果に (「成功」または「失敗」ではなく) 「エラー」が含まれる 1 つ以上のテストが表示されます。
このような場合、FakeTable 操作はロールバックされず、テーブルはフェイク状態のままになります。
内部では、FakeTable はテーブルの名前を変更し、その新しいコピーを作成します。名前の変更が発生すると、操作は tSQLt.Private_RenamedObjectLog に記録されます。
たとえば、次のコードを使用して、tSQLt が正常にロールバックできないエラーを再現できます。
EXEC tSQLt.NewTestClass 'SOF_Example'
GO
CREATE TABLE SOF_Example.MyTable (i INT);
GO
INSERT INTO SOF_Example.MyTable (i) VALUES (5);
GO
CREATE PROCEDURE SOF_Example.[test fake a table]
AS
BEGIN
EXEC tSQLt.FakeTable 'SOF_Example.MyTable';
INSERT INTO SOF_Example.MyTable (i) VALUES (12);
COMMIT;
END;
GO
EXEC tSQLt.Run 'SOF_Example';
次のコードを使用して、名前が変更されたテーブル ログを調べることができます。
SELECT OriginalName, SCHEMA_NAME(schema_id) + '.' + name AS [Name of Renamed Table], create_date
FROM tSQLt.Private_RenamedObjectLog
JOIN sys.objects ON ObjectId = object_id;
テストを何度も再実行した場合、偽造された各テーブルのログに多くのエントリが含まれている可能性があります。create_date を使用して、元のデータがどちらに含まれているかを判断できます。
以上のことから、データを保存しなければならないデータベースでは、テスト ケースを記述して実行しないことが最善です。最良の方法は、ユーザー データを含まないデータベースを使用することです (多くても重要な構成データのみ)。空のデータベースから開発および単体テストを行う必要があります。データが入力されたデータベースは、統合、使いやすさ、パフォーマンスなど、他の形式のテストに使用する必要があります。
これは、テーブルを元の位置に戻すことのみを処理します (これは OP と私が両方とも抱えていた問題であるため) が、テーブルをドロップする行をモンキー化すると、おそらく他のオブジェクト タイプで動作するようになります。
DECLARE @cmd nvarchar(MAX) = '';
WITH x AS (
SELECT TOP 10000
PL.Id AS Id
,PARSENAME(PL.OriginalName,1) AS OriginalName
,ISNULL(SO.name,'') AS name
,QUOTENAME(SCHEMA_NAME(ISNULL(SO.schema_id,1))) AS SchemaName
,ISNULL(SEP.major_id,-1) AS major_id
FROM tSQLt.Private_RenamedObjectLog PL
LEFT JOIN sys.objects SO
ON ObjectId = object_id
LEFT JOIN sys.extended_properties SEP
ON SEP.major_id = SO.object_id
AND SEP.name = 'tSQLt.FakeTable_OrgTableName'
ORDER BY SO.create_date DESC
)
SELECT @cmd = @cmd
+ CASE WHEN x.name = '' OR OriginalName = x.name
THEN N'DELETE tSQLt.Private_RenamedObjectLog WHERE Id = ' + CAST(x.Id AS nvarchar) + N';'
ELSE N'DROP '
+ N'TABLE' --Replace this with a CASE statement to deal with other object types
+ N' ' + SchemaName + '.' + QUOTENAME(x.OriginalName) + '; '
+ NCHAR(13) + NCHAR(10) + N'EXEC sp_rename ''' + SchemaName + N'.'
+ QUOTENAME(x.name) + N''',''' + OriginalName + N''';'
+ NCHAR(13) + NCHAR(10) + N'IF OBJECT_ID('''+SchemaName + N'.' + QUOTENAME(x.name)+N''') IS NULL'
+ NCHAR(13) + NCHAR(10) + N'BEGIN'
+ CASE WHEN x.major_id != -1
THEN NCHAR(13) + NCHAR(10) + N' EXEC sp_dropextendedproperty ''tSQLt.FakeTable_OrgTableName'',''SCHEMA'','''
+ PARSENAME(SchemaName,1) + N''',''TABLE'',''' + OriginalName + N''';'
ELSE ''
END
+ NCHAR(13) + NCHAR(10) + N' DELETE tSQLt.Private_RenamedObjectLog WHERE Id = ' + CAST(x.Id AS nvarchar) + N';'
+ NCHAR(13) + NCHAR(10) + N'END'
END
+ NCHAR(13) + NCHAR(10)
+ NCHAR(13) + NCHAR(10)
FROM x;
--/* <-Remove leading dashes to execute
PRINT @cmd;
--*/EXEC (@cmd);
私はtSQLtで同じ問題を抱えていて、テーブルtSQLt.Private_RenamedObjectLogの内容を使用してすべてを復元することができました
このテーブルは tSQLt フレームワークによって維持され、偽造された元のテーブルの名前と、一時 (偽の) テーブルの SQL ObjectID を含むことが証明されています。次のクエリを使用すると、偽のテーブルのリストと、一時的に名前が変更された名前 (tSQLt_tempobject_3815e077fea84c7c などのtSQLtによって生成されるランダムな名前) が生成されます。
SELECT
ObjectId, OriginalName,
OBJECT_SCHEMA_NAME(ObjectId) AS SchemaName,
OBJECT_NAME(ObjectId) AS TemporaryName
FROM
tSQLt.Private_RenamedObjectLog
SSMS でオブジェクト エクスプローラーを更新すると、これらのランダムな名前のテーブルが実際に存在し、元のデータが実際に含まれていることがわかりました (うわー!!)。
次に、次のことを行いました。
- 念のため、
ROLLBACK TRANSACTION
それを整理してみました。そうではありませんでした。 - データベースをバックアップしました(めちゃくちゃになっていたとしても)
- 偽のテーブルを削除しました (つまり、一時的な名前ではなく、元の名前のテーブル)
各テーブルにこれを使用して、テーブルの名前を (一時的な名前で) 元の名前に戻します。
EXEC sp_rename 'schema.tempname', 'originalname'
を使用して、テーブルが戻ったことを知った後、テーブル tSQLt.Private_RenamedObjectLog をクリアしました
DELETE FROM tSQLt.Private_RenamedObjectLog
復元スクリプトを自動生成する手順を簡単に作成できます。たぶん、tSQLt に既に 1 つあるかもしれません - 誰かそれについて知っていますか?
私は以前にこの質問に答えたことを知っています!この回答がより役立つことを願っています。また、質問が古いこと。SpyProcedureを使用して、偽の関数またはプロシージャに対処した人は他にいません。
はい、この問題は、トランザクションの外部で tSQLt テストのコードを実行することによって簡単に発生します。tSQLt はトランザクション内のすべてのテストを実行するため、すべての偽造などはテストの最後にロールバックされます。tSQLt は、それらを偽造するためにテーブルなどの名前を変更します。これは通常、ロールバックされます。SpyProcedureを実行するとログ テーブルも作成されるため、SpyProcedure を再度実行しようとするとクラッシュする可能性があります。したがって、トランザクションでテストを実行しない場合、これらの変更はロールバックされません。幸いなことに、tSQLt には、すべてを復元するために必要なすべての情報が含まれています。
最初ROLLBACK TRANSACTION
にそれを整理する場合に備えて試してください。そうでない場合は、元のテーブルなどがtSQLtのテーブルに記録されているかどうかを確認して、偽造/名前変更されたものを確認してください。
SELECT ObjectId, OriginalName,
OBJECT_SCHEMA_NAME(ObjectId) AS SchemaName, OBJECT_NAME(ObjectId) AS TemporaryName
FROM tSQLt.Private_RenamedObjectLog
レコードが返された場合は、復元できる可能性が高くなります。ただし、最初にデータベースをバックアップしてください。
ここで、偽造されたオブジェクトを削除する SQL コードを生成し (元のオブジェクトがまだ存在することをテストした後)、元のオブジェクトの名前を実際の名前に戻します。私の知る限り、tSQLt はテーブル、ビュー、関数、およびSpyProcedureを使用したプロシージャを偽造できるため、ほとんどすべての状況で機能するはずです。SpyProcedure によって作成されたログ テーブルも削除されます。
DECLARE @SQL_work NVARCHAR(MAX) = '';
DECLARE @template NVARCHAR(MAX) =
'IF OBJECT_ID(''%s.%s'') IS NOT NULL BEGIN -- check original still exists
DROP %s %s.%s -- deleted faked object
EXEC sp_rename ''%s.%s'', ''%s''
END
';
SELECT
@SQL_work = @SQL_work +
FORMATMESSAGE (CAST (@template AS NVARCHAR (MAX)),
QUOTENAME(OBJECT_SCHEMA_NAME(r.ObjectId)), OBJECT_NAME(ObjectId),
CASE WHEN type IN ('U', 'V') THEN 'TABLE'
WHEN type IN ('FN','FS','TF','IF','FT') THEN 'FUNCTION'
WHEN type = 'P' THEN 'PROCEDURE'
END,
QUOTENAME(OBJECT_SCHEMA_NAME(r.ObjectId)), OriginalName,
QUOTENAME(OBJECT_SCHEMA_NAME(r.ObjectId)), OBJECT_NAME(ObjectId),
PARSENAME (OriginalName, 1)
) +
CASE WHEN type = 'P'
THEN FORMATMESSAGE ('DROP TABLE %s.%s_SpyProcedureLog
', QUOTENAME(OBJECT_SCHEMA_NAME(r.ObjectId)),
PARSENAME (OriginalName, 1)
)
ELSE ''
END +CHAR(13)+CHAR(10)
FROM
tSQLt.Private_RenamedObjectLog AS r
JOIN
sys.objects AS o ON r.ObjectId = o.object_id
PRINT @SQL_work
PRINT 'DELETE FROM tSQLt.Private_RenamedObjectLog'
上記はコードを生成して出力し、物事を元に戻します。生成されたスクリプトを慎重に実行することをお勧めします。つまり、パーツを 1 つずつ実行し、他のすべてが機能した場合DELETE
にのみ最後のステートメントを実行します。
これがうまくいったかどうか、またはコードを改善できるように問題が発生したかどうかを知りたいです。
すべての tSQLt テストは単なるストアド プロシージャであることに注意してください。これらは単純な EXEC で実行できます。tSQLt.Run を使用しないと、トランザクションを作成せずにテスト プロシージャが実行される場合があります。つまり、特に FakeTable の効果は、テストの完了時にロールバックされません。SQL Server でのトランザクションの操作は tSQLt 機能の中心的な原則であるため、注意が必要です。
私たちの組織では、すべての開発者が利用することが期待されるテスト手順テンプレートを提供しています。テンプレートが最初に行うことは、コードがトランザクション内で実行されているかどうかを確認することです。そうでない場合は、適切なメッセージで中止されます。これですべてのトランザクション関連の問題が解決されるわけではありませんが、テストが裸で実行されていないことが保証されます。