次の方法で共有


Microsoft Fakes でのコード生成、コンパイル、名前付け規則

この記事では、Fakes コードの生成とコンパイルのオプションと問題について説明し、Fakes によって生成される型、メンバー、およびパラメーターの名前付け規則について説明します。

必要条件

  • Visual Studio Enterprise

  • .NET Framework プロジェクト

  • Visual Studio 2019 Update 6 では、.NET Core、.NET 5.0 以降、SDK スタイルのプロジェクトサポートがプレビューされ、Update 8 では既定で有効になっています。 詳細については、「 Microsoft Fakes for .NET Core および SDK スタイルのプロジェクト」を参照してください。

コードの生成とコンパイル

スタブのコード生成を構成する

スタブ型の生成は、 .fakes ファイル拡張子を持つ XML ファイルで構成されます。 Fakes フレームワークは、カスタム MSBuild タスクを通じてビルド プロセスに統合され、ビルド時にそれらのファイルを検出します。 Fakes コード ジェネレーターは、スタブ型をアセンブリにコンパイルし、プロジェクトへの参照を追加します。

次の例は、 FileSystem.dllで定義されているスタブ型を示しています。

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
    <Assembly Name="FileSystem"/>
</Fakes>

型フィルタリング

.fakes ファイルでフィルターを設定して、スタブする必要がある型を制限できます。 StubGeneration 要素の下に無制限の数の Clear 要素、Add 要素、Remove 要素を追加して、選択した型の一覧を作成できます。

たとえば、次の .fakes ファイルは、System 名前空間と System.IO 名前空間の型のスタブを生成しますが、System の "Handle" を含む型は除外します。

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="mscorlib" />
  <!-- user code -->
  <StubGeneration>
    <Clear />
    <Add Namespace="System!" />
    <Add Namespace="System.IO!"/>
    <Remove TypeName="Handle" />
  </StubGeneration>
  <!-- /user code -->
</Fakes>

フィルター文字列では、単純な文法を使用して、照合を行う方法を定義します。

  • 既定では、フィルターは大文字と小文字を区別せず、部分文字列を一致させます。

    el が "hello" と一致する

  • フィルターの末尾に ! を追加すると、大文字と小文字が区別される正確な一致になります。

    el! が "hello" と一致しません

    hello! が "hello" と一致する

  • フィルターの末尾に * を追加すると、文字列のプレフィックスと一致します。

    el* が "hello" と一致しません

    he* が "hello" と一致する

  • セミコロンで区切られたリスト内の複数のフィルターは、論理和として結合されます。

    el;wo は "hello" と "world" と一致します

スタブ 具象クラスと仮想メソッド

既定では、すべての非シール クラスに対してスタブ型が生成されます。 .fakes 構成ファイルを使用して、スタブ型を抽象クラスに制限することができます。

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="mscorlib" />
  <!-- user code -->
  <StubGeneration>
    <Types>
      <Clear />
      <Add AbstractClasses="true"/>
    </Types>
  </StubGeneration>
  <!-- /user code -->
</Fakes>

内部型

Fakes コード ジェネレーターは、生成された Fakes アセンブリからアクセスできる型に対して、シム型とスタブ型を生成します。 Shimmed アセンブリの内部型を Fakes とテスト アセンブリに表示するには、生成された Fakes アセンブリとテスト アセンブリを表示するシミングされたアセンブリ コードに InternalsVisibleToAttribute 属性を追加します。 次に例を示します。

// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes")]
[assembly: InternalsVisibleTo("FileSystem.Tests")]

厳密に名前が付けられたアセンブリの内部型

強名が付けられた shimmed アセンブリにおいて、その内部型にアクセスしたい場合:

  • テスト アセンブリと Fakes アセンブリの両方に厳密な名前を付ける必要があります。

  • テスト アセンブリと Fakes アセンブリの公開キーを、shimmed アセンブリの InternalsVisibleToAttribute 属性に追加します。 厳密に名前付けされたシムアセンブリのアセンブリコードにおける属性の例がどのように表示されるかを以下に示します。

    // FileSystem\AssemblyInfo.cs
    [assembly: InternalsVisibleTo("FileSystem.Fakes",
        PublicKey=<Fakes_assembly_public_key>)]
    [assembly: InternalsVisibleTo("FileSystem.Tests",
        PublicKey=<Test_assembly_public_key>)]
    

シムされたアセンブリに厳密名が付けられている場合、Fakes フレームワークは生成された Fakes アセンブリに対して自動的に厳密な署名を行います。 テスト アセンブリに厳密に署名する必要があります。 アセンブリ Strong-Named 参照してください。

Fakes フレームワークでは、生成されたすべてのアセンブリに署名するために同じキーが使用されるため、このスニペットを開始点として使用して、 fakes アセンブリの InternalsVisibleTo 属性を shimmed アセンブリ コードに追加できます。

[assembly: InternalsVisibleTo("FileSystem.Fakes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e92decb949446f688ab9f6973436c535bf50acd1fd580495aae3f875aa4e4f663ca77908c63b7f0996977cb98fcfdb35e05aa2c842002703cad835473caac5ef14107e3a7fae01120a96558785f48319f66daabc862872b2c53f5ac11fa335c0165e202b4c011334c7bc8f4c4e570cf255190f4e3e2cbc9137ca57cb687947bc")]

代替キーを含む .snk ファイルへの完全なパスを .fakes ファイルの KeyFileFakes\ 要素のCompilation属性値として指定することで、Fakes アセンブリに別の公開キー (shimmed アセンブリ用に作成したキーなど) を指定できます。 例えば次が挙げられます。

<-- FileSystem.Fakes.fakes -->
<Fakes ...>
  <Compilation KeyFile="full_path_to_the_alternate_snk_file" />
</Fakes>

次に、代替 .snk ファイルの公開キーを、shimmed アセンブリ コードの Fakes アセンブリの InternalVisibleTo 属性の 2 番目のパラメーターとして使用する必要があります。

// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes",
    PublicKey=<Alternate_public_key>)]
[assembly: InternalsVisibleTo("FileSystem.Tests",
    PublicKey=<Test_assembly_public_key>)]

上記の例では、 Alternate_public_key 値と Test_assembly_public_key は同じにすることができます。

ビルド時間の最適化

Fakes アセンブリのコンパイルにより、ビルド時間が大幅に増加する可能性があります。 個別の一元化されたプロジェクトで .NET System アセンブリとサード パーティ製アセンブリの Fakes アセンブリを生成することで、ビルド時間を最小限に抑えることができます。 このようなアセンブリはコンピューター上でほとんど変更されないため、生成された Fakes アセンブリを他のプロジェクトで再利用できます。

単体テスト プロジェクトから、プロジェクト フォルダーの FakesAssemblies の下に配置されているコンパイル済みの Fakes アセンブリへの参照を追加します。

  1. テスト プロジェクトに一致する .NET ランタイム バージョンを使用して、新しいクラス ライブラリを作成します。 Fakes.Prebuild と呼びましょう。 プロジェクトから class1.cs ファイルを削除します。不要です。

  2. Fakes が必要なすべてのシステムアセンブリとサードパーティ製アセンブリへの参照を追加します。

  3. アセンブリとビルドごとに .fakes ファイルを追加します。

  4. テストプロジェクトから

    • Fakes ランタイム DLL への参照があることを確認します。

      %ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.QualityTools.Testing.Fakes.dll

    • Fakes を作成したアセンブリごとに、プロジェクトの Fakes.Prebuild\FakesAssemblies フォルダー内の対応する DLL ファイルへの参照を追加します。

アセンブリ名の競合を回避する

チーム ビルド環境では、すべてのビルド出力が 1 つのディレクトリにマージされます。 複数のプロジェクトで Fakes を使用している場合、異なるバージョンの Fakes アセンブリが互いにオーバーライドされることがあります。 たとえば、TestProject1 は .NET Framework 2.0 の mscorlib.dll を偽装し、TestProject2 は .NET Framework 4 の mscorlib.dll を偽装します。それによって、両方とも mscorlib.Fakes.dll という Fakes アセンブリが生成されます。

この問題を回避するために、Fakes は 、.fakes ファイルを追加するときに、プロジェクト以外の参照のバージョン修飾された Fakes アセンブリ名を自動的に作成する必要があります。 バージョンが修飾された Fakes アセンブリ名を作成すると、そのアセンブリ名にバージョン番号が埋め込まれます。

アセンブリ MyAssembly とバージョン 1.2.3.4 を指定すると、Fakes アセンブリ名は MyAssembly.1.2.3.4.Fakes です。

このバージョンを変更または削除するには、 .fakes の Assembly 要素の Version 属性を編集します。

attribute of the Assembly element in the .fakes:
<Fakes ...>
  <Assembly Name="MyAssembly" Version="1.2.3.4" />
  ...
</Fakes>

Fakesの命名規則

Shim 型とスタブ型の命名規則

名前空間

  • .Fakes サフィックスが名前空間に追加されます。

    たとえば、 System.Fakes 名前空間には System 名前空間の shim 型が含まれています。

  • Global.Fakes には、空の名前空間の shim 型が含まれています。

    型名

  • shim プレフィックスが型名に追加され、shim 型名が作成されます。

    たとえば、ShimExample は Example 型の shim 型です。

  • スタブ プレフィックスが型名に追加され、スタブ型名が作成されます。

    たとえば、StubIExample は IExample 型のスタブ型です。

    型引数と入れ子になった型構造体

  • ジェネリック型引数がコピーされます。

  • shim 型のネストされた型構造がコピーされます。

Shim デリゲート プロパティまたはスタブ デリゲート フィールドの名前付け規則

空の名前から始まる、フィールドの名前付けの基本的な規則:

  • メソッド名が追加されます。

  • メソッド名が明示的なインターフェイス実装である場合、ドットは削除されます。

  • メソッドがジェネリックの場合は、 Ofn が追加されます。 n はジェネリック メソッド引数の数です。

    プロパティ ゲッターやセッターなどの特殊なメソッド名は、次の表に示すように扱われます。

メソッドが...の場合は Example 追加されたメソッド名
コンストラクター .ctor Constructor
静的 コンストラクター .cctor StaticConstructor
メソッド名が "_" で区切られた 2 つの部分で構成される アクセサー (プロパティ getter など) kind_name (一般的なケースですが、ECMA では適用されません) NameKind(両方の部分が大文字にされ、スワップされている)
プロパティPropを取得するためのゲッター PropGet
プロパティのセッター Prop PropSet
イベント追加機能 Add
イベント削除ツール Remove
2 つの部分で構成される演算子 op_name NameOp
例: + 演算子 op_Add AddOp
変換演算子の場合、戻り値の型が追加されます。 T op_Implicit ImplicitOpT

  • インデクサーのゲッターとセッター は、プロパティと同様に扱われます。 インデクサーの既定の名前は Item
  • パラメーター型 名は変換され、連結されます。
  • オーバーロードのあいまいさがない限り、戻り値の型は無視されます。 オーバーロードのあいまいさがある場合は、戻り値の型が名前の末尾に追加されます。

パラメーター型の名前付け規則

Given 追加された文字列は...
T T

名前空間、入れ子になった構造体、およびジェネリック ティックは削除されます。
out パラメーターout T TOut
ref パラメーターref T TRef
配列型T[] TArray
多次元配列T[ , , ] T3
ポインターT* TPtr
ジェネリック型T<R1, ...> TOfR1
型のジェネリック型引数!iC<TType> Ti
メソッドのジェネリック メソッド引数!!iM<MMethod> Mi
入れ子になった型N.T N が追加され、次に T

再帰規則

次の規則が再帰的に適用されます。

  • Fakes は C# を使用して Fakes アセンブリを生成するため、無効な C# トークンを生成するすべての文字は "_" (アンダースコア) にエスケープされます。

  • 結果の名前が宣言型のメンバーと競合する場合は、01 から始まる 2 桁のカウンターを追加することによって番号付けスキームが使用されます。

継続的インテグレーションでの Microsoft Fakes の利用

Microsoft Fakes アセンブリの生成

Microsoft Fakes は、Visual Studio Enterprise でのみ使用できる機能です。 そのため、Fakes アセンブリの生成では、プロジェクトのビルド時に Visual Studio ビルド タスク を使用する必要があります。

別の方法として、Fakes アセンブリを継続的インテグレーション (CI) システムに直接チェックインし、 MSBuild タスクを利用する必要があります。 この方法を選択する場合は、次のコード スニペットに示すように、生成された Fakes アセンブリへのアセンブリ参照をテスト プロジェクトに含める必要があります。

<Project Sdk="Microsoft.NET.Sdk">
    <ItemGroup>
        <Reference Include="FakesAssemblies\System.Fakes.dll"/>
    </ItemGroup>
</Project>

この参照は、SDK スタイルのプロジェクト (つまり、.NET Core、.NET 5 以降、.NET Framework) 用に手動で追加する必要があります。これらのプロジェクトは、アセンブリ参照を暗黙的に追加するようになりました。 このメソッドを使用する場合は、親アセンブリが変更されるたびに Fakes アセンブリを更新してください。