5

質問

偽物を作成するときに読み取り専用フィールドをどのように処理しますか?

バックグラウンド

私はASP.NetMVCを使用する初心者の段階にあり、例としてStevenSandersonのSportsStoreとScottGuのNerdDinnerを使用しています。私が今直面した小さな問題の1つは、偽物を作成するときに読み取り専用プロパティをどのように操作するかです。LINQToSQLを使用しています。

私のインターフェースは:

public interface IPersonRespository
{   
    Person GetPerson(int id);
}

そして私の偽物は

public class FakePersonRepository
{
    public Person GetPerson(int id)
    {
        return new Person {id="EMP12345", name="John Doe", age=47, ssn=123-45-6789, totalDrWhoEpisodesWatched=42};
    }
}

これが私の問題です。フィールドid、ssn、およびtotalDrWhoEpisodesWatchedは読み取り専用であるため、上記のコードは実際には機能しません。ただし、偽の新しい人物を作成して読み取り専用プロパティを設定する方法がわかりません。解決策があると確信していますが、検索ではまだ解決策に出くわしていません。

更新:潜在的な解決策としての継承+プロパティの非表示?

私はまだ問題のしっかりした解決策を決めていません。偽物を作成する目的でドメインクラスを変更するという概念は嫌いです。私にとって、テストを行うためにドメインクラスにマークアップを追加することは、追加された結合の形式です。つまり、テストの実装への結合です。現在、別の可能性を調査しています。これは、Personから継承するが、新しい読み取り/書き込みプロパティでプロパティを非表示にするFakePersonクラスを作成することです。

public class FakePerson: Person
{
    public new int age { get; set; }
    public new string ssn { get; set; }
    public new int totalDrWhoEpisodesWatched { get; set; }
}

これまでのところ、この解決策は私が傾いている方法です。それはリスコフの置換原則を破ります、しかしそれはテストプロジェクトで私をそれほど悩ませません。解決策として、これに対する批判やフィードバックを聞いてうれしいです。

勝者:モックフレームワーク

Moqがその仕事をしているようです。継承によってプロパティを非表示にする最後のソリューションは実際には機能しますが、Moqを使用することで、より保守しやすい標準化された機能セットを取得できます。他のモックフレームワークにもこの機能があると思いますが、チェックしていません。Moqは、私が今間違いなく書いている、最初の模擬執筆にとってより簡単であると言われています。

4

5 に答える 5

6

テストでPersonタイプをモックすることを検討してください。Moqの使用例:

var mock = new Mock<Person>();
mock.SetupGet(p => p.id).Returns("EMP12345");
mock.SetupGet(p => p.ssn).Returns("123-45-6789");
mock.SetupGet(p => p.totalDrWhoEpisodesWatched).Returns(42);
return mock.Object;

それ以外の場合は、LINQtoSQLがこれらの読み取り専用プロパティをどのように設定するかを調べてみてください。

編集:上記を試みて、Moqが「オーバーライドできないメンバーのセットアップが無効です:p => p.id」というメッセージを含む呼び出しをスローしArgumentExceptionた場合は、プロパティを仮想としてマークする必要があります。これは、ゲッターをオーバーライドするプロパティごとに実行する必要があります。SetupGet

LINQ to SQLでは、これはORデザイナーでプロパティを選択して実行できます。次に、[プロパティ]ウィンドウで[継承修飾子]を[仮想]に設定します。

于 2009-06-09T07:06:23.423 に答える
1

クラスのコンストラクターでのみ読み取り専用プロパティを設定できます。Personオブジェクトには、id、ssn、およびtotalDrWhoEpisodesWatchedを受け入れるコンストラクターが必要です。もちろん、これがlinqtosqlで生成されたオブジェクトである場合、コードが自動生成されるため、これを変更する際に問題が発生する可能性があります。

マップされたオブジェクトを使用してリポジトリに公開することを検討できます...したがって、実際にlinqtosqlオブジェクトをモデルとして使用する必要はありません。

于 2009-06-08T15:41:36.693 に答える
1

.NETでは、セッターを「内部」としてマークし、InternalsVisibleToアセンブリ属性を使用して、内部をテストアセンブリから見えるようにすることができます。そうすれば、セッターは公開されませんが、引き続きアクセスできます。

注:質問には.NETのタグが付いていませんが、オブジェクト初期化構文の使用法に基づいていると思います。私の仮定が間違っていた場合、この提案は当てはまりません(もちろん、使用している言語に同等の機能がない限り)。

于 2009-06-08T16:13:26.160 に答える
0

テスト用の場合は、リフレクションの使用を検討してください。それはあなたのドメインモデルをいじることを含みません。

たとえば、FactoryBaseクラスを取得しました。これは、リフレクションを使用して、パラメーターを介したラムダ式によって必要なpropを設定します(このように)。魅力のように機能します-新しいファクトリの作成は、リポジトリタイプとデフォルトのエンティティデータを定義するだけです。

于 2009-06-08T20:12:23.947 に答える
0

私もMoqを使用しています。私はそれが大好きで、それは素晴らしい働きをします。しかし、Moqを使い始める前に、私は多くの偽物を書きました。これが私が偽物を使って問題を解決する方法です。

偽物には「本番」実装にはない追加のメソッドが含まれる可能性があるため、読み取り専用部分の設定を処理するために、偽物の実装にいくつかの追加メソッドを追加します。

このような:

public class FakePersonRepository : IPersonRespository
{
    private IDictionary<int, Person> _people = new Dictionary<int, Person>();

    public Person GetPerson(int id)  // Interface Implementation
    {
        return _people(id);
    }

    public void SetPerson(int id, Person person)  // Not part of interface
    {
         _people.Add(id, person);
    }

}
于 2009-08-19T16:16:58.473 に答える