署名つきアセンブリをテストする
VS2010 で DLL を作成し、それを VS 標準の MSTest で単体テストしている。ところが DLL とテストプロジェクトに署名をしたところ、テストプロジェクトをビルドする段で下記のエラーが発生した。
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\TeamTest\Microsoft.TeamTest.targets(14,5): error : 値が有効な範囲にありません。
ネットを漁っても有効な解決策を見つけることはできなかったが、 #if ディレクティブを使用することでこのエラーを回避することができたので報告する。
プロジェクト構成は、テスト対象である "Common" と、テスターである "CommonTest" の二つ。
当初は署名なしで開発を進めていたが、電子署名が供給されたので "Common" に対して署名を設定することにした。
ところが "Common" の internal メソッドをテストするために、 "InternalsVisibleTo" 属性を設定している。
従って "CommonTest" にも署名が必要になるが、そしたらビルド時に上記のようなエラーが発生するようになった次第。
まずは "Common" と "CommonTest" の署名のあり/なしの組み合わせを調べてみた。
すると、双方とも署名なしの場合のみビルドが通った。
"Common" に署名をつけると
フレンド アセンブリ参照 'CommonTest' は無効です。厳密な名前の署名つきアセンブリはその InternalsVisibleTo 宣言内で公開キーを指定しなければなりません。
というエラーが出る。それではと思って "CommonTest" に署名をつけてその公開キーを指定すると、冒頭のエラーが出て "CommonTest" のビルドが通らない。
次に "Microsoft.TeamTest.targets" でぐぐってみると、以下の2件だけがヒットした。
- Visual Studio 2008のプライベートアクセッサ機能 - 中の技術日誌ブログ
- C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.targets(14,5): error : Collection was modified; enumeration operation may not execute - okumuri
えーとつまり、アクセサによるプライベートメソッドへのアクセスが原因か?
いやいや、今回はパブリックメソッドだけのテストで済ませるのは不安ありまくり。
かといって、今更リフレクションでどうにかするのもチト、いや、かなりきつい。
2012/03/29 追記 ---
非常に単純なプロジェクトで試してみたら、アクセサによるプライベートメソッドのテストを作ってみても問題なくビルドが通った。
件のプロジェクトは継承やCOM連携なども仕込んであるので、まだ他に原因があるのかもしれない。
--- 追記 ここまで
そこでコンパイルシンボル "TEST" が有効な場合は "InternalsVisibleTo" 属性を有効にした上で CommonTest プロジェクトもビルドし、無効な場合は "AssemblyKeyFile" 属性で署名ファイルを指定するようにした。
// AssemblyInfo.cs #if TEST [assembly: InternalsVisibleTo( "CommonTest" )] #else [assembly: AssemblyKeyFile( "Common.snk" )] #endif
その結果、パスワードなしの署名ファイル(.snk)でならビルドが通るようになった。
しかし、パスワード付きの署名ファイル(.pfx)だと以下のエラーが発生する。
エラー CS1548: アセンブリ '<アセンブリファイル>' を署名しているときに暗号に失敗しました -- 'アセンブリ署名のエラー -- パラメーターが間違っています。 '
AssemblyKeyFile にパスワードを指定できない以上、当然っちゃー当然だわな。
そこで今度は sn.exe で .pfx ファイルからキーペアを CSPコンテナに突っ込み、AssemblyKeyName 属性でキーコンテナ名を参照することにした。
C:\>sn -i CommonPass.pfx CommonKeyPair
// AssemblyInfo.cs #if TEST [assembly: InternalsVisibleTo( "CommonTest" )] #else [assembly: AssemblyKeyName( "CommonKeyPair" )] #endif
その結果、パスワード付きキーペアであってもビルドに成功した。
ただし、AssemblyKeyFile、AssemblyKeyName のどちらを使用した場合も、ビルド時に下記の警告が発生する。
警告 CS1699: コマンド ライン オプション '/keycontainer' を使用するか、'AssemblyKeyName' 以外の適切なプロジェクト設定を使用してください。
リリース用の設定で警告が出るのは少しばかり気持ちが悪いんだが。
もちろん、警告の意図を知った上で無視してはいるんだけど。
他に何かいい手はないものかなぁ。