0

Tools.Client というプロジェクトで Person クラスを定義しました。これは、Web サービス API のラッパーです。Person は、サービスによって返された XML で構築されます。

public class Person
{
  internal Person(XElement personElement)
  {
    this.FirstName = personElement.Element("first_name").Value;
    this.LastName = personElement.Element("last_name").Value;

    this.Jobs = new List<Job>();
    foreach (var jobElement in personElement.Elements("jobs"))
    {
      this.Jobs.Add(new Job(jobElement));
    }
  }

  public string FirstName {get; private set;}
  public string LastName {get; private set;}
  public ICollection<Job> {get; private set;}
}

Tools.Analysis という別のプロジェクトに Analyzer という別のクラスがあります。このプロジェクトには、API クライアントから取得したデータに対して実行する分析ロジックが含まれています。

private readonly ICollection<Person> _people;
public Analyzer(ICollection<Person> people)
{
  _people = people;
}

public AnalysisResult Analyze()
{
  var result = new AnalysisResult();

  foreach (var person in _people)
  {
    // do some analysis, store data in the result
  }

  return result;
}

Analyzer クラスの Analyze メソッドの単体テストを書きたいのですが、次の問題を回避する方法がわかりません。

  1. Person には、XElement パラメーターを持つ内部コンストラクター メソッドがあります。単体テストで XElement オブジェクトを手動で作成したくありません。

  2. Personにはプライベートセッターがあります(そうすべきだと思うので、Tools.ClientのユーザーがAPIから返されたデータを変更することは望ましくありません)。この問題は、同様の構造を持つ Job への追加の依存関係によって悪化します。

これに対するいくつかの解決策を考えることができますが、時間の経過とともにどれが最も保守しやすいかわかりません:

  1. IPerson および IJob インターフェイスを作成し、これらのインターフェイスのモックまたは単純なテスト実装を使用します。
  2. 簡単にテストできるようにパブリック セッターを公開します (繰り返しますが、これはあまり好きではありません)。InternalsVisibleTo 属性を使用して内部セッターを使用することもできると思います (パブリックほど悪くはありませんが、それでも私が望むものではありません)。
  3. XML 解析をコンストラクターの外に移動し、コンストラクターにパラメーター firstName、lastName、jobs を取らせます。コンストラクターは引き続き内部にすることができます。アセンブリで InternalsVisibleTo 属性を使用する必要があるだけです。
4

2 に答える 2

4

Personxml 解析を別のファクトリのようなクラスに移動し、Person不変の値オブジェクトのようなクラスを作成する必要があると思います。このようにして、それらをモックする必要はありません。テスト用のPersonとの実際のインスタンスを作成できるはずです。JobAnalyzer

于 2013-03-28T03:46:44.970 に答える
0

セッターを公開したくないことに同意します。あなたは今、不変のクラスを持っています。それを簡単にあきらめるべきではありません。

値オブジェクトのインターフェイスは問題ありませんが、多くの場合過剰に設計されています。より良い解決策がある場合は、それを避けてください。

オプション 3 を使用します。Xml の解析は、実際には別のクラスの責任です。Personデータ オブジェクトのみにする必要があります。

それができない場合は、少なくともそれなしでコンストラクターを作成してください。コンストラクターが発散する可能性があるため (コンストラクター同士を簡単に呼び出すことができないため)、これは素晴らしいことではありませんが、現在の場所よりも段階的に優れています。

public class Person
{
  internal Person(XElement personElement)
  {
    this.FirstName = personElement.Element("first_name").Value;
    this.LastName = personElement.Element("last_name").Value;

    this.Jobs = new List<Job>();
    foreach (var jobElement in personElement.Elements("jobs"))
    {
      this.Jobs.Add(new Job(jobElement));
    }
  }

  internal Person(string firstName, string lastName, ICollection<Job> jobs)
  {
     //set properties
  }

  public string FirstName {get; private set;}
  public string LastName {get; private set;}
  public ICollection<Job> {get; private set;}
}
于 2013-03-28T03:55:44.820 に答える