UI として機能するものを指定していませんか? これは GUI アプリですか、それとも Web アプリですか? これは一般的なアプローチにある程度の影響を与えますが、いくつかのヒントを与えるために、私の経験を共有します. 私はswingを使用して多くのGUIアプリを作成しましたが、それが私のベースラインになります.
そのため、GUI を可能な限り薄くし、コンポーネントの表示のみを担当するロジックを配置する傾向があります。これを実現するには、プレゼンテーション モデル ( http://martinfowler.com/eaaDev/PresentationModel.html ) やパッシブ ビュー ( http://martinfowler.com/eaaDev/PassiveScreen.html )などのよく知られたデザイン パターンを使用できます。
次に、ビジネス ロジックのテストを開始します。一般的なガイドラインは次のとおりです。
- 外部リソース (ファイル、DB など) を使用せず、代わりにテスト用の固定入力を提供する Fakes または Mocks に置き換えます。
- 依存関係の動作ではなく、クラスの動作のみをテストします
- 複雑な入力を避けるようにしてください
- 上記のパターンを使用して、ビュー レイヤーをモックし、ビューの特定のメソッドが同期レイヤーで呼び出されたかどうかのみをテストできます。
お役に立てば幸いです。そうでない場合は、何かが少しあいまいであるかどうかをお知らせください。また、問題にどのように取り組みたいか、アプローチに関してどのような懸念があるか、例を挙げていただければ幸いです。
@例
私は JavaFx の経験がないので、Swing でそれを行う方法を示そうとします。この例では、モックとは何か、何のためにあるのかを知っていることを前提としています。
まず、シン クライアントで最も重要な機能は何かを考えてみましょう。私はそのようなものに行きます。ユーザーが xml ファイルを開くと、アプリはそれをなんらかの形式で表示します。(フォームは重要ではありません。ツリーである可能性があり、テーブルまたはグリッドである可能性があります。ビューであるため、今は気にしません)
基本的なシナリオは、ユーザーがファイルを選択し、アプリがそのファイルを開いて解析し、結果が表示されるというものです。このシナリオを「Open Results」と呼びましょう。
最初のテスト:
class OpenResultsShould{
@Test
public void loadResults() {
Data fake = mock (Data.class);
ViewInterface view = mock(ViewInterface.class); // mocking view
when(view.getFilename()).thenReturn("file.xml"); // we specify that when getFileName() method of view mock will be called "file.xml" string will be returned.
ApplicationModelInterface appModel = mock(ApplicationModelInterface.class); // mocking app model
when(appModel.getDataForView()).thenReturn(fake);
OpenResultsAction openResults = new OpenResultsAction( view, appModel );
openResults.actionPerformed(new ActionEvent());
verify(view).getFileName(); // checks that view.getFileName was called within actionPerdormed()
verify(appModel).load("file.xml"); // check that appModel.load( ) with file.xml as parameter was called within actionPerformed()
verify(appModel).getDataForView(); // similar to above
verify(view).loadDataFromModel( fake ); // finally I check if loadDataFromModel on view was called.
}
}
このテストの目的は、OpenResultsAction が機能するかどうかを確認することです。ここでは、解析されたものと gui が正しいデータを持っているかどうかをテストしていません。特定のオブジェクトの特定のメソッドが呼び出されたかどうかをテストします。このテストでは、アクション クラス、ビュー、および applicationModel 間のコントラクトも指定します。これはインターフェースを介して行われます。したがって、次のステップでテストされる具体的な実装を後で提供できます。次に、この例をできるだけ短くするためにスキップする実装を提供します。
それで、次は何ですか。GUI はまったくテストされないので、ApplicationModel テストを行います。最初のテストでは、applicationModelInterface にメソッド load(String filename); が必要であることを指定しました。そして、それが具体的に実装されているかどうかをテストします。
class ApplicationModelShould{
@Test
public void loadModelFromFile() {
XMLDocument xml = new XMLDocumentFake();
XMLFileLoader xFileLoader = mock(XMLFileLoader.class);
when(xFileLoader.load("file.xml").thenReturn( xml );
ApplicationModelInterface appModel = new ConcreteApplicationModel( new FileLoaderFake() );
appModel.load("plik.xml"); // it should call xFileLoader and then parse returned xml document.
doReturn(xml).when(xFileLoader).load("plik.xml"); // verifies if xFileLoader returned xml when appModel.load called it's load method.
Data expectedResult = populateExpectedResults();
assertEquals( appModel.getDataForView().equals( expectedResult ) );
}
}
XMLDocument とは? xml ファイルの内容を格納します。ファイル行のベクトルとして表すことができます。AppModelLoader はそれをオブジェクトに解析します。XFileLoader は、単体テストでファイル操作をなくすことができるもう 1 つのレイヤーです。ここでは嘲笑されていますが、実際のアプリでは、xml ファイルを読み取って XMLDocument を返すものに置き換える必要があります。データは、解析されたデータを格納するために使用されるクラスです。xml のコンテンツが「<Person><name>Tom</name><age>34</age></Person>」の場合、データは次のようになります。
class Data{
private Person person;
Data(Person person){ this.person = person; }
...
};
class Person{
private String name;
private int age;
.... setters, getters and constructors
}
そして、それは基本的にそれです。もちろん、たとえば、 view.getFileName() が OpenResultsAction で空の文字列を返す場合 (ユーザーが JFileChooser でキャンセルを押した場合) など、さらに多くのテストが必要です。すべてのクラスをテストする場合は、GUI 部分を作成して結合します。
それが理にかなっているかどうか教えてください。