2

私は最近、アプリケーションをテスト可能にするためにビジネス ロジックをデータ アクセスから分離する最善の方法について質問しました (こちら)。Jeff Sternal のおかげで、データ アクセス用のインターフェイスを作成し、その具体的な実装をアプリケーションのトップ レベルから BL に渡しました。しかし今、ファイル アクセス方法をビジネス ロジックから分離する方法を見つけようとしています。

データベースからデータセットにデータをロードし、ロードされたデータをフォーマットし (フォーマットは外部 xml ファイルに保存されます)、最終的にデータセットをファイルにシリアル化する関数があるとします。したがって、テスト容易性をサポートするには、ファイル システムにアクセスするすべての関数を何らかのインターフェイスに移動する必要があります。しかし、最初に、dataset.WriteXml(file) を呼び出すだけで非常に便利だと思いますが、テストを容易にするために、インターフェイスを作成し、dataset.WriteXml() をその実装に移動する必要があります。 . 2 つ目は、ファイル システムにアクセスするすべてのメソッドを 1 つのインターフェイスに移動すると、SRP の原則に違反することになります。

4

5 に答える 5

2

コードをもう少し分割する必要があると思います...

あなたは言う:私が関数を持っているとしましょう

  1. データベースからデータセットにデータをロードし、
  2. ロードされたデータのフォーマット (フォーマットは外部の xml ファイルに保存されます) および
  3. 最後に、データセットをファイルにシリアル化します。

少なくとも 3 ~ 4 ジョブのように聞こえます...

コードをさらに分割すると、他のすべての機能を回避することなく、これらの各機能をテストできます。

Dataset.WriteXML を実行したいだけなら、それをテストする必要はありません。それは非常にうまく機能するフレームワーク関数です。そこにいくつかのモックを入れて、それを偽造してみてください。どのくらい正確にあなたのソリューションに依存します...

コメントへの回答:

これらすべての小さなクラスを独自のテストで作成すると、テストが容易になり、関数も小さくコンパクトになります (-> テストが容易になります) データセットの内容が必要なものであるかどうかをテストします。 xml ファイルに正しくシリアライズされます。また、他のロジックに依存せずに、フォーマッターがその機能を正しく実行するかどうかもテストします。データ アクセスもテストしますが、DB にアクセスせずに (再びスタブ/モック)

これがすべて正常に機能することを確認したら、データセットの適切なメソッドが呼び出されることを「ただ」確認します。これで満足するはずです。これは、他の部分をすでに分離してテストしたためです。

単体テストで難しいのは、意味のあるテストを取得することです。それらは「高速」かつ「シンプル」であるべきです

テストを高速化するために、制御できないものには触れないでください。

  • ウェブサービス
  • ファイルシステム
  • データベース
  • Com オブジェクト

それらを単純にするために、クラスを単一のタスク、つまりSRPが登場する場所に集中させます。これはすでに述べました。この回答を見てください...「SOLID」開発の他の原則も指摘します

https://stackoverflow.com/questions/1423597/solid-principles/1423627#1423627

于 2009-09-22T16:20:38.403 に答える
1

簡単な要約として、これを本当にテスト可能にしたい場合は、次をお勧めします。

  1. データ フォーマット コードを新しいクラス (モックに使用できるインターフェイスを実装するクラス) に抽出します。
  2. このクラスを渡すと、DataSet.
  3. 新しいクラス が、モックもできるDataSetas を返すようにします。IXmlSerializable

現在のコードを見ずに、いくつかの仮定を立てる必要があります (あまり多くないことを願っています!) - おそらく、現在のコードは次のようになります。

public class EmployeeService {

    private IEmployeeRepository _Repository;

    public EmployeeService(IRepository repository) {
        this._Repository = repository;
    }

    public void ExportEmployeeData(int employeeId, string path) {

        DataSet dataSet = this._Repository.Get(employeeId);
        // ... Format data in the dataset here ...
       dataSet.WriteXml(path);
    }
}

このコードはシンプルで効果的ですが、テストできません (副作用なし)。さらに、そのすべてのロジックを 1 か所にまとめることは、単一責任の原則に違反します。

あなたのニーズにもよりますが、おそらく大丈夫です!SRP を満たすことは常に単なる目標であり、設計に影響を与える他の要因とテスト容易性のバランスを取る必要があります。

ただし、責任をもう少し分離してテスト可能にしたい場合は、書式設定ロジックを独自のクラス ( を実装するIEmployeeDataSetFormatter) に移動してIEmployeeDataSetFormatterから、このメソッド呼び出しに を挿入します (または、のように、サービスのコンストラクターIEmployeeRepository)。データをフォーマットするメソッドは を返すIXmlSerializableので、安全で分離されたテストのためにモックを作成できます。

public interface IEmployeeDataSetFormatter {
    IXmlSerializable FormatForExport(DataSet dataSet);
}

public class EmployeeDataSetFormatter: IEmployeeDataSetFormatter {
    public IXmlSerializable FormatForExport(DataSet dataSet) {
        // ... Format data in the dataset here ...
        return (IXmlSerializable) dataSet;
    }
}

public void ExportEmployeeData2(int employeeId, string path, IEmployeeDataSetFormatter formatter) {

    DataSet dataSet = this._Repository.Get(employeeId);

    IXmlSerializable xmlSerializable = formatter.FormatForExport(dataSet);

    // This is still an intermediary step - it's probably worth
    // moving this logic into its own class so you don't have to deal
    // with the concrete FileStream underlying the XmlWriter here
    using (XmlWriter writer = XmlWriter.Create(path)) {
        xmlSerializable.WriteXml(writer);
    }
}

これには明確なコストがかかります。追加のインターフェイス、追加のクラス、およびもう少し複雑さが追加されます。しかし、それはテスト可能で、よりモジュール化されています (良い意味で、私はそう思います)。

于 2009-09-22T16:21:42.803 に答える
1

追加のクラスに進みます。テストするときは、次のほうが簡単です。

  • データセット エクスポーター/ライターの場合 - 変更されたデータがライターに渡されることを確認します
  • フォーマッタの場合 - フォーマット ロジックを確認してください

これは、あなたがしないという意味ではありません:

  • dataSet.WriteXml を使用します。v. 単純なクラスで行うだけです ... 1 つのライナーとして、それに焦点を合わせた統合テストを追加する必要はありません ... しかし、ストア上の l8r が外部で言う場合システム、他のコードに影響を与えることなく、他の実装でそうすることを選択するかもしれません
  • データセット エクスポーター/ライターには、単純なファイル ライターとは別のクラスを使用します。

v. シンプルな依存性注入を使用している限り、実際にはすべてをシンプルに保つだけです...これにより、短期的にも長期的にもより良い結果が得られます。

Ps。テスト中にファイルシステムにヒットしないことは重要です。テストの数が増えると、テストを高速に実行する必要があるため、テストの最初の「クイック」アクセスで表示されるものに惑わされないでください

于 2009-09-22T17:04:56.217 に答える
0

あなたの説明から、あなたのコードが何をしているのかは完全には明らかではありません。あなたのコードが行っている最も重要なことは何ですか? フォーマットですか?xml の書き込みをわざわざテストしないでください。とにかくそれをどのように確認しますか?

ファイルを読み書きする必要がある場合は、コードを変更して、streamreader/streamwriter または textreader/textwriter を渡し、呼び出し元のコードでテスト用の memorystream や実際の i/ o 生産中。

于 2009-09-22T16:11:37.660 に答える
0

orWriteXml()を取るのバージョンを使用して、このオブジェクトがコードに渡されるようにコードを設定してから、モック オブジェクトでパスをテストすることができます。StreamTextWriter

于 2009-09-22T16:12:45.620 に答える