質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

4回答

5600閲覧

NUnitでファイル選択ダイアログが表示されるメソッドのテスト方法

Ryzna

総合スコア85

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2015/02/23 11:14

お世話になります。初質問です。よろしくお願いします。
NUnit1週間目くらいの初心者です。

現在下記環境にて標準のFolderBrowserDialogによるファイル選択を含むメソッドのテストを作成しようとしております。

環境:
framework:4.5.1
言語:C#
テスト対象:windowsアプリケーション(any cpu)
NUnit:2.6.3

当然のことながらダイアログが出てきてしまうので、何らかの処理をしてあげる必要があるとは思っているのですが、UIオートメーションでやるのが普通なのか、NUnitに対応した何かがあるのか調べまわってる最中です。

もし「普通こうするよ」ってやり方がございましたらご教授いただければ幸いです。
もしそもそもそういうメソッドはテストできないとかの情報でも歓迎です。

よろしくお願いします。

以上

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

モックフレームワークを使用します。

細かい説明は省きますが、
モックフレームワークを使用すると、
メソッドの返り値などを自由に設定することが出来ます。

例えば、以下のようなモックフレームワークがあります。

  • Microsoft Fakes
  • Microsoft Moles (Microsoft Fakes の前身)
  • Moq
  • Rhino

投稿2015/02/23 13:30

ryunix

総合スコア1656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/02/24 01:58

ご回答ありがとうございます。 環境に不足がございまして申し訳ありませんでした。 ご紹介いただきましたMoqを利用させていただいており、Moqを利用した方法を検討していたのですが実コードにテストコードを埋め込まないといけなさそうだったので倦厭しておりました;
ryunix

2015/02/24 02:28

Moqは使用したことないので、正確ではありませんが、実コードにテストコードが埋め込まれると言うのはどういう状態でしょうか?
Ryzna

2015/02/24 02:37

今回のファイル選択ダイアログが表示されるメソッドのテストに限ってしまいますが、実処理側にテストならばファイル選択ダイアログコントロールの代わりにモックを使用するよう切り替えるイメージですね。。。
ryunix

2015/02/24 02:44

テストメソッドでMockの実装をするので、実処理側は変更不要だと思いますが、違いますか?
Ryzna

2015/02/24 03:12

ファイル選択ダイアログを表示する処理を含むメソッドのテストなのでファイル選択ダイアログをモックで作るということだと理解しましたが・・・もしかして違っていましたか?
Ryzna

2015/02/24 03:14

すみません。これだとあいまいですね; 「ファイル選択ダイアログのインスタンスを自分で生成して表示して選択結果を返すメソッドのテスト」という意味です; そもそも質問自体に問題ありましたね;
ryunix

2015/02/24 03:14

いえ、その認識です。 テストメソッドの中でMockを作る認識ですが、どうでしょうか?
Ryzna

2015/02/24 03:21

テスト対象を大雑把に再現してみました。 public string GetDirectoryPath() { string result = null; var retry = true; var fbd = new FolderBrowserDialog() // ←こいつをモックにする認識 while (retry) { if (fbd.ShowDialog() != DialogResult.OK) break; if (本当にこのパスでいいのか?) // いいなら結果返す result = folderBrowser.SelectedPath; } return result; }
Ryzna

2015/02/24 03:29

↑無限ループですね; 修正できないので気にしない方向でお願いします。
ryunix

2015/02/24 03:45

サンプル提示ありがとうございます! Moqについて調べましたが、interfaceかvirtualなメソッドしかモック出来ないんですね。 失礼しました。 Moqでは力不足ですね... FakesもしくはMolesなら、実処理に手を入れず、モックすることが出来ます!
Ryzna

2015/02/24 03:49

oh・・・もう・・・ 残念ながら既にMoqでプロジェクトが進んでしまっているので次のプロジェクトまでにご紹介頂きました"Fakes"、"Moles"を使いこなせるようになってガン押しして行きたいと思いますorz
ryunix

2015/02/24 03:54

oh, 申し訳ない... :( FakesとMolesはMicrosoft謹製で、非常に強力でinterfaceとか関係なくモック出来るんです... お力になれず申し訳ありません orz
Ryzna

2015/02/24 04:23

とんでもない。 こちらこそ情報ありがとうございました。 またよろしくお願いします。
ryunix

2015/02/24 04:38

はい、またよろしくお願いします :)
guest

0

とりあえず今回は業務絡みだったのでテストコードの実装を完了しました。

サンプルコード用意して無いですが今回行ったテストの概要を残しておきます。

概要:
・ UIオートメーションを使用しました。
・ フォルダ選択ダイアログが開くのを監視して下記処理を行うスレッドを別途用意
1. ダイアログ上のツリー(ControlType.Tree)と OKボタン(ControlType.Button)を検索・取得
2. ツリー上の項目(ControlType.TreeItem)をテスト対象のフォルダパスに沿って展開する(ExpandCollapsePattern.Pattern)
3. 終着点となる項目が見つかったらその項目を選択状態にする
4. 1で取っておいたOKボタンを押す(InvokePattern)

・ スレッドの処理が正常に終わったことと、テスト対象のメソッドの戻り値が期待値どおりかの両方をもって評価としました。

結局のところですが、仮に GetDirectoryPath メソッド自体からダイアログを表示する処理を追い出しても、アプリケーションのどこかに表示させる処理があって、それに対してもテストを作らなきゃいけないと気づいてしまいました。でしたので、もうテストを手動でやるかテスト見逃してもらうか、上記のようにダイアログを外部から操作するようにするかしか思いつきませんでした。

もっと良い方法があるぜ!っという方はどしどし情報提供お願いします。

P.S.
今回の手法で自分用のコード作ったら貼っておくかもしれません。
僕らのたびはまだはじまったばk(ry

投稿2015/02/25 12:22

Ryzna

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/02/25 12:29

尚、今のところNUnit(+Moq)でどうにかできる問題ではないという認識です。その辺もご意見お待ちしております。
guest

0

ウィンドウを開く処理だけ括り出すのはどうでしょう?

プロダクトコード

lang

1public class Xxx 2{ 3 ・・・ 4 5 public string GetDirectoryPath() 6 { 7 string result = null; 8 var fbd = new FolderBrowserDialog(); 9 10 while (result == null) 11 { 12 // ShowDialog をデリゲートにして括り出し。 13 // if (fbd.ShowDialog() != DialogResult.OK) 14 if (OnShowDialog(fbd) != DialogResult.OK) 15 break; 16 17 if (本当にこのパスでいいのか) 18 result = fbd.SelectedPath; 19 } 20 21 return result; 22 } 23 24 internal Func<FolderBrowserDialog, DialogResult> OnShowDialog = fbd => fbd.ShowDialog(); 25 // internal は InternalsVisibleTo 属性でテストにだけ公開。 26}

テストコード

lang

1[TestFixture] 2public class XxxTest 3{ 4 // 例えば、GetDirectoryPath は FolderBrowserDialog がキャンセルされた場合、null を返すことを確認する。 5 [Test] 6 public void GetDirectoryPath_should_return_null_if_FolderBrowserDialog_is_cancelled() 7 { 8 // Arrange 9 var m = new Mock<Func<FolderBrowserDialog, DialogResult>>(); 10 m.Setup(_ => _(It.IsAny<FolderBrowserDialog>())).Returns(DialogResult.Cancel); 11 12 var sut = new Xxx(); 13 sut.OnShowDialog = m.Object; 14 15 16 // Act 17 var result = sut.GetDirectoryPath(); 18 19 20 // Assert 21 m.VerifyAll(); 22 Assert.IsNull(result); 23 } 24}

ちなみに私は、UI が絡む処理は、よほどのことが無い限り手動でテストする派です。テストコードのメンテナンスコストが、割に合わないことがほとんどなので :)

投稿2015/02/24 11:46

urasandesu

総合スコア24

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/02/25 11:58

ご提案ありがとうございます。 ここまでくるとフォルダ選択ダイアログのラッパー作ってインターフェイス抜き出して外部から受け取るようにしちゃおうかな・・・とか思うレベルですね・・・。 まさにたった今この部分のテストコードが書きあがりまして概要は質問に追記しておきますが、まさに「割に合わない」の一言でした。 UIテスト用のフレームワーク(というかテストツール?)でキーボード・マウスのインプットをシミュレートしてくれるようなのがあった気がしますがその有り難さがわかりました。。。 コスパ大事。
guest

0

ベストアンサー

今回の場合、自動テストの途中でユーザの操作が必要なダイアログが開くために、そこでテストが中断してしまうことが問題なのだと思います。なら、あたかもダイアログを開いたかのようにふるまってくれる仕組みがあれば、中断しなくて済むわけです。
Mockフレームワークは、その「ふりをしてくれる」仕組みです。
たとえば、下記のようなテストしたいコードがあるとします。

lang

1 var fbd = new FolderBrowserDialog(); 2 fbd.Description = "フォルダを選択してください"; 3 DialogResult dr = fbd.ShowDialog(); 4 if (dr == DialogResult.OK) { 5 return fbd.SelectedPath; 6 } 7 return null;

ここで呼び出されるFolderBrowserDialogを、実物と同じようなメソッドやプロパティを持つものに置き換え、ダイアログを開かずに済ませるのがMockフレームワークの役割です。
この時、開発中のコードはできるだけそのままで済ませたいので、条件コンパイルなどでnamespaceを入れ替えるなどの工夫が必要です。
たとえば、こんな感じでしょうか。MockというnamespaceがMock版のコントロール群を持つとします。

lang

1#if FOR_TEST 2 var fbd = new Mock.FolderBrowserDialog(); 3#else 4 var fbd = new FolderBrowserDialog(); 5#endif

投稿2015/02/23 16:46

shinosan

総合スコア209

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/02/24 01:39

ご回答ありがとうございます。 やはりこうなってしまうのですね。。。 出来れば本番コードそのまま試験できれば・・・なんて思っていましたがテストの実装でグダグダしても仕方が無いので割り切って行きたいと思います。
shinosan

2015/02/24 01:57

フレームワークによっては、名前空間まで合わせて、参照先のDLLを差し替えるだけにできるものもあるかもしれません。設定などが面倒になりそうですが。
Ryzna

2015/02/24 02:39

ぁー・・・ それはもしかしてFolderBrowserDialogの完全な名前空間でモックアップを用意するイメージってことですかね?;
shinosan

2015/02/24 03:21

理論上は可能ですが、確かDLLの一部だけを置き換えるのは出来ないはずなので、全部のクラスのモックアップが必要になってしまいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問