WPFアプリケーションのModel部分のUnitTestをしたい。
が、Model部にResourceを参照する部分があって、これがユニットテストから参照するとNullアクセスで吹っ飛んでしまう。
という現象にちょっとハマったので自分用メモ。
リソースは ResourceDictionary/StringDictionary.xaml に定義されています。
で、これの App.Current がnullになってる。
まぁね、ユニットテストだからね。
public static int GetIntResouce(string name)
{
return (int)App.Current.Resources[name];
}
じゃあユニットテストクラスのコンストラクタで App インスタンスを生成すれば良いのか。
これはnullじゃなくなるけど、リソースが空っぽ状態なので、駄目。
複数のテストを同時に実行しようとすると、インスタンスが複数つくろうとしてしまうので、それも駄目。
var x = new Application();
解決方法
なんか色々と方法はあるっぽいけど、ちょっと強引な方法をとりました。
- ユニットテストのビルド前にWPFアプリのリソースファイルをコピーする
- ユニットテストのコンストラクタで上記を読み込む
まず1
ユニットテストプロジェクトのプロパティから、ビルド前のイベントを登録しておきます。
WPFアプリプロジェクトを hogehoge とします。
こんなことせず、普通にリンクで追加しとけば良いんや。
md $(TargetDir)ResourceDictionary > NUL 2>&1
xcopy "$(ProjectDir)..\hogehoge\ResourceDictionary\StringDictionary.xaml" "$(ProjectDir)ResourceDictionary\" /Y
ユニットテストプロジェクトの管理ファイルにもしておきます。
Git管理していたら、コピー先の ResourceDictionary/StringDictionary.xaml はコミットはしません。
元ファイルを変更する度にこっちにも差分があるよって言われたら鬱陶しいしね。
次に2
ユニットテストクラスのコンストラクタで、リソースを読み込みます。
var targetAssembly = typeof(hogehoge.Views.MainWindow).Assembly;
Application.ResourceAssembly = targetAssembly;
var rd = Application.LoadComponent(new Uri(@"ResourceDictionary/StringDictionary.xaml", UriKind.Relative));
if (Application.Current == null)
{
var x = new Application();
}
Application.Current.Resources =(System.Windows.ResourceDictionary)rd;
とりあえずこれで解決。
うまいやり方じゃない気がするけど、大事なのはユニットテストを通すことなので、とりあえずOKにする。
ちな、要素ごとにリソースの定義をわけている場合、面倒なのでAdd関数で追加しとく。
速度なんて知らん。
var dm = (ResourceDictionary)Application.LoadComponent(new Uri(@"ResourceDictionary/DialogMessage.xaml", UriKind.Relative));
foreach (string key in dm.Keys)
{
Application.Current.Resources.Add(key, dm[key]);
}
他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。