ファイルシステムとファイルに関連するロジックを実装するクラスがいくつかあります。たとえば、このロジックの一部として次のタスクを実行しています。
現在、このロジックにはすべて何らかのワークフローがあり、何かが正しくない場合は例外がスローされます(たとえば、構成ファイルが特定のフォルダーの場所で見つからないなど)。さらに、このロジックには Managed Extensibility Framework(MEF) が関係しています。チェックするこれらのファイルの一部は、手動でMEFアグリゲートなどにロードするマネージDLLであるためです。
ここで、これらすべてを何らかの方法でテストしたいと思います。さまざまなテストケースをカバーし、それらに対してコードを実行するHDD上に、いくつかの物理的なテストフォルダーを作成することを考えていました。たとえば、作成できます:
これは正しいアプローチでしょうか?しかし、このシナリオでコードをどのように正確に実行するかはわかりません...アプリケーション全体を実行して、これらのモックされたフォルダをチェックするように指示するのは確かにしたくないです。これらのファイルシステムオブジェクトに対してコードを実行する一種の「ユニットテスト」を作成するために、ユニットテストフレームワークを使用する必要がありますか?
一般的に、これはすべてこの種のテストシナリオの正しいアプローチですか?他のより良いアプローチはありますか?
まず第一に、それは外部リソースに触れることなくロジックをテストするユニットテストを書く方が良いと思う。ここには2つのオプションがあります。
単体テストでは、MEFなどの外部ライブラリのロジックをテストする必要はありません。
二番目に、あなたが統合テストを書きたいなら、あなたは「幸せなパス」テスト(すべてがOKであるとき)と境界ケースであなたのロジックをテストするいくつかのテストを書く必要があります(ファイルまたはディレクトリが見つかりません)。 @Sergey Berezovskiyとは異なり、テストケースごとに個別のフォルダーを作成することをお勧めします。主な利点は次のとおりです。
単体テストと統合テストの両方について、-通常の単体テストフレームワークを使用できます(NUnitやxUnit.NETなど)。このフレームワークを使用すると、ビルドサーバー上の継続的統合シナリオでテストを簡単に起動できます。
両方の種類のテストを作成する場合、統合テストからユニットテストを分離する必要があります(テストの種類ごとに個別のプロジェクトを作成できます)。その理由:
インターフェイスの背後にあるファイルシステムへの呼び出しを抽象化することにより、ユニットテストでできるだけ多くのロジックをテストする必要があります。依存性注入と FakeItEasy などのテストフレームワークを使用すると、ファイルやフォルダーを操作するためにインターフェイスが実際に使用または呼び出されていることをテストできます。
ただし、ある時点で、ファイルシステムで動作する実装もテストする必要があります。これは統合テストが必要な場所です。
テストする必要があるのは、比較的孤立しているようです。テストするのは、独自のファイルシステム上の独自のファイルとディレクトリだけです。データベース、または複数のユーザーを含む他の外部システムなどをテストしたい場合、事態はより複雑になる可能性があります。
このタイプの統合テストを最適に実行するための「公式ルール」を見つけるとは思わないが、あなたは正しい軌道に乗っていると思う。努力すべきいくつかのアイデア:
あなたの状況では、2つのメインフォルダーを設定します。1つはすべてが本来の状態(つまり正常に動作している)であるフォルダーと、すべてのルールが破られているフォルダーです。
これらのフォルダーとその中のファイルを作成してから、各フォルダーをZip圧縮し、テストクラスでロジックを作成して、各フォルダーを解凍します。
これらは実際にはテストではありません。代わりに、テストシナリオを設定するための「スクリプト」と考えてください。これにより、テスト中にメインの統合テストが変更または混乱した場合でも、フォルダーとファイルを簡単かつ迅速に削除および再作成できます。それらをテストクラスに入れる理由は、テスト中に作業するのと同じインターフェースから簡単に実行できるようにするためです。
状況ごとに1セットずつ、テストクラスの2つのセットを作成します(正しく設定されていないフォルダーと、壊れたルールのフォルダー)。これらのテストを、自分にとって意味のあるフォルダーの階層に配置します(状況の複雑さに応じて)。
ユニット/統合テストにどれだけ精通しているかは明らかではありません。いずれにせよ、 NUnit をお勧めします。 Should
の拡張機能も使用したいです。これらの両方をNugetから取得できます。
install-package Nunit
install-package Should
Should-packageを使用すると、次のような方法でテストコードを記述できます。
someCalculatedIntValue.ShouldEqual(3);
someFoundBoolValue.ShouldBeTrue();
テストを実行するために、いくつかのテストランナーが利用可能であることに注意してください。個人的には、Resharperに組み込まれたランナーで実際の経験しかありませんでしたが、私はそれに非常に満足しており、推奨することに問題はありません。
以下は、2つのテストを含む簡単なテストクラスの例です。 1つ目では、Shouldの拡張メソッドを使用して期待値をチェックしますが、2つ目では何も明示的にテストしないことに注意してください。これは、[ExpectedException]でタグ付けされているためです。つまり、テストの実行時に指定されたタイプの例外がスローされないと失敗します。これを使用して、ルールの1つが破られたときに適切な例外がスローされることを確認できます。
[TestFixture]
public class When_calculating_sums
{
private MyCalculator _calc;
private int _result;
[SetUp] // Runs before each test
public void SetUp()
{
// Create an instance of the class to test:
_calc = new MyCalculator();
// Logic to test the result of:
_result = _calc.Add(1, 1);
}
[Test] // First test
public void Should_return_correct_sum()
{
_result.ShouldEqual(2);
}
[Test] // Second test
[ExpectedException(typeof (DivideByZeroException))]
public void Should_throw_exception_for_invalid_values()
{
// Divide by 0 should throw a DivideByZeroException:
var otherResult = _calc.Divide(5, 0);
}
[TearDown] // Runs after each test (seldom needed in practice)
public void TearDown()
{
_calc.Dispose();
}
}
これらすべての準備が整ったら、テストシナリオを作成および再作成し、それらに対して簡単かつ繰り返し可能な方法でテストを実行できるはずです。
編集:コメントで指摘されているように、 Assert.Throws()は別のオプションです 必要に応じて例外がスローされることを保証します。個人的には、タグバリアントが好きですが、 with parameters 、エラーメッセージなども確認できます。別の例(カスタムエラーメッセージが電卓からスローされていると仮定):
[ExpectedException(typeof(DivideByZeroException), ExpectedMessage="Attempted to divide by zero" )]
public void When_attempting_something_silly(){
...
}
単一のテストフォルダーを使用します。さまざまなテストケースでは、コンテキストセットアップの一部として、そのフォルダーに異なる有効/無効ファイルを配置できます。テストの分解では、これらのファイルをフォルダーから削除するだけです。
例えば。 Specflow :
Given configuration file not exist
When something
Then foo
Given configuration file exists
And some dll not exists
When something
Then bar
適切なファイルをフォルダーにコピーする/しないとして、各コンテキスト設定手順を定義します。 table を使用して、フォルダーにコピーするファイルを定義することもできます。
Given some scenario
| FileName |
| a.config |
| b.invalid.config |
When something
Then foobar
あなたのプログラムのアーキテクチャが良いアドバイスを与えるのを知りませんが、試してみます
フレームワークロジックを構築し、同時実行の問題とファイルシステムの例外をテストして、明確に定義されたテスト環境を確保します。
問題のあるドメインのすべての境界をリストしてみてください。数が多すぎる場合は、問題が広範に定義されすぎており、分解する必要がある可能性を考慮してください。システムがすべてのテストに合格するために必要な必要十分条件の完全なセットは何ですか?次に、すべての条件を調べて、個々の攻撃ポイントとして扱います。そして、あなたが考えることができるすべての方法をリストし、それを破る。あなたがそれらをすべて見つけたことを自分自身に証明してみてください。次に、それぞれのテストを作成します。
最初に環境について上記のプロセスを実行し、最初に満足のいく標準に合わせてそれを構築およびテストしてから、ワークフロー内のより詳細なロジックを作成します。テスト中に環境と詳細なロジックとの間に依存関係が発生した場合、反復が必要になる場合があります。