ソフトウェアテストに関するガイダンスが必要です。
私は物事を複雑にしすぎていますが、私は自分が間違っていること、または物事を行う別の方法を見るにはあまりにも固執しています。
同じプライベートメソッドを使用しているパブリックメソッドがいくつかあります。
プライベートメソッド自体:
- その特定の役割のために多くのシナリオを処理する必要があります
- 同じインスタンス内のフィールド/プロパティ/メソッドと緊密に連携します
プライベートメソッドはすべてのシナリオをカバーするために5つのテストが必要であり、6つのパブリックメソッドによって使用されるとします。
質問
次に、少なくとも
5x6
テストが必要ですか?パブリックメソッドごとにプライベートメソッドのテストを再利用するにはどうすればよいですか?
繰り返されるテストのリファクタリングに関する例/記事はありますか?
例
始めるとき()
- if_file_exists_load_entries ()
- if_file_missing_load_last ()
- if_no_files_create_new_entries ()
- if_exception_clear_entries_and_log ()
- loaded_entries_init_called ()
- Other tests
OnUserLoadCustom()
- if_file_exists_load_entries _AND_STORE_AS_LAST()
- if_file_missing_load_last _AND_STORE_AS_LAST_AND_WARNING_MESSAGE()
- if_no_files_create_new_entries _AND_WARNING_MESSAGE()
- if_exception_clear_entries_and_log _AND_ERROR_MESSAGE()
- loaded_entries_init_called _AND_SUCCESS_MESSAGE()
- Other tests
OnRecover()
- if_file_exists_load_entries _AND_INFO_MESSAGE()
- if_file_missing_load_last _AND_INFO_MESSAGE()
- if_no_files_create_new_entries _AND_INFO_MESSAGE()
- if_exception_clear_entries_and_log _AND_ERROR_MESSAGE_AND_SHUTDOWN()
- loaded_entries_init_called _AND_SUCCESS_MESSAGE()
- Other tests
Strategyパターンを使用してプライベートメソッドをカプセル化することを検討しているので、それ(およびパブリックメソッド)を分離してテストできます。
ただし、次の理由で使用するのが適切ではありません。
- 実行時に互換性のある動作をするつもりはありません
- テストを簡単にするためにパターンを使用するのは間違っているようです
アップデート#1
私の質問は、プライベートメソッドの動作についてパブリックインターフェイスをテストすることに関するものです。しかし、私は多くの重複したテスト方法になってしまいます(上記の私の例を参照してください)。
戦略パターンでは、必要なのは次のとおりです。
- 戦略のすべてのパスをテストします(基本的に、プライベートメソッドをテストします)
- すべてのパブリックメソッドがストラテジーを呼び出すことを確認します(ここでモックオブジェクトを簡単に使用でき、呼び出されたことを確認できます)
しかし、私が述べたように、テストを容易にするためだけにパターンを導入するべきではないと思います。本当に必要な場合を除いて、私はこのアプローチを延期しています。
アップデート#2
重複を減らす最初の試み:
独自のクラスにグループ化されたプライベートメソッドテスト(Behaviour1Test)
- GetTestCases()は、この動作に関連するテストケースのリストを返します
このテストを必要とするすべてのパブリックメソッドは、公開するインターフェイスを実装します
- 整える()
- 活動()
- 主張する()
例えば:
// Public method tests
[TestFixture]
public class PublicMethodTests: IBehaviour1Test
{
// Behaviour 1
Behaviour1Test _behaviour1;
IEnumerable<TestCaseData> Behaviour1TestCases{ get { return _behaviour1.GetTestCases(); } }
[Test]
[TestCaseSource("Behaviour1TestCases")]
public void RunBehaviour1Test(Action<IBehaviour1Test> runTestCase)
{
runTestCase(this);
}
// ==============================
// Behaviour 1 Arrange/act/assert
void IBehaviour1Test.Arrange(){}
void IBehaviour1Test.Assert(object result){}
object IBehaviour1Test.Act()
{
return _model.PublicMethod();
}
// Other tests
}
// Implement this in order to run Behaviour1 test cases
interface IBehaviour1Test
{
void Arrange();
object Act();
void Assert(object retValue);
}
// Collection of tests for behaviour 1
public class Behaviour1Test
{
// Generate test cases
IEnumerable<TestCaseData>() GetTestCases()
{
yield return new TestCaseData((Action<IBehaviour1Test>)Test_1);
yield return new TestCaseData((Action<IBehaviour1Test>)Test_2);
yield return new TestCaseData((Action<IBehaviour1Test>)Test_3);
}
void Test_1(IBehaviour1Test impl)
{
// Arrange
impl.Arrange(); // public method's arrange
Test1Setup(); // Arrange for this test
// Act
var result = impl.Act();
// Assert
Test1Assert(result); // Assert for this test
impl.Assert(result); // Assert on public method
}
void Test_2(IBehaviour1Test impl){}
void Test_3(IBehaviour1Test impl){}
}
このように、プライベートメソッドの動作に新しいテストケースを追加する必要がある場合は、BehaviourTestに1回追加するだけで、それを含むすべてのパブリックメソッドテストが更新されます。