4

MS Dynamics Crm で、封印されたクラスと読み取り専用プロパティを使用していくつかのオブジェクトを返す状況があります (内部コンストラクターまたは内部プロパティ セットの使用のみを推測できます)。そして、これらの人は私が使用できるインターフェースから継承していません。明らかに、このコードを制御できれば、より多くの制御が可能になりますが、基盤となる MS Dynamics フレームワークに含まれているため、少し行き詰っています。

モック/オーバーライドしたいクラスはAliasedValueと呼ばれます。私がそれをモックしたい理由は、ダイナミクスへの呼び出しをシミュレートしようとしていて、エイリアス値が返されているふりをしたいからです。

シナリオは次のとおりです。Dynamics が返すサンプル エンティティを作成します。次のようなものです。

var new_entity = new Entity("new_entity")
    {
        Attributes = new AttributeCollection
            {
                {"new_name", "BR"},
                {"createdon", DateTime.Now.AddDays(-1).Date},
                {"new_field", "My field"},
                {"new_contact", new AliasedValue {*****} }
            }
    };

したがって、「連絡先」エンティティを参照しています (リアルタイムでこれは AliasedValue として返されます)。テスト中に、コードがこのフィールドに返される可能性のある特定の値を処理することを確認したいと思います (たとえば、エイリアス値を処理する方法を知っている、リンクされた連絡先が返されない場合は爆発しないなど)。

したがって、AliasedValue へのリンクをクリックすると、プロパティが読み取り専用であることがわかります...そのため、テスト データを設定できません...

次に、独自のクラスを作成して全体をオーバーライドするつもりでしたが、封印されています...

それに加えて、おそらくご想像のとおり、Moq はシールされたクラスをモックしようとするのが好きではありません。

これを行うには「より良い」モッキングフレームワークを購入する必要があると読みましたが、この1つのことを回避するためだけに余分なお金を払う必要はありません。

これを回避するための素敵な小さな解決策を誰かが手に入れましたか?

明確化のための更新


これがどのように返されるかのサンプルは次のとおりです。上記のオブジェクトを返すためにモックされるサービスがあります。または、実際に返されるのは、上記のオブジェクトを含むコレクションです。したがって、これは次のようになります。

var service = new Mock<IOrganizationService>();
service
    .Setup(s => s.RetrieveMultiple(null))
    .Returns(new EntityCollection (new List<Entity> {new_entity}));

これは素晴らしいことです。上記のエンティティを返して、やりたいことを実行できます。したがって、上記のエンティティを作成し、モックされたサービスを介してそれを返した後、「EntityCollection」で上記を取得します。エンティティを取得したら、次のようにプロパティにアクセスします。

var aliasedContact = (AliasedValue)new_entity.Attributes["new_contact"];

たぶん私はばかげているかもしれませんが、答え(Lunivoreによる)がこれをどのように解決するかはよくわかりません...(フィードバックを得るためにコメントを追加しています...)

4

2 に答える 2

6

非常に単純なアダプタクラスを追加して、サードパーティのライブラリから自分自身を抽象化します。検査によってテストできます。ターゲットクラスを拡張するのではなく、その上に新しいクラスを作成するだけです。メソッドの名前やプロパティなどを同じにすることができます(必須ではありません)。つまり、封印されたクラスに委任するだけです。

封印されたクラスを返すクラスが1つある場合は、両方をラップします。したがって、次のようになります。

var crmWrapper = new MSDynamicsCrmWrapper(_myMsDynamicsCrm);
var entityWrapper = crmWrapper.AliasedValue(url);

そして、crmWrapperは次のことを行います。

public EntityWrapper AliasedValue(Url url) 
{
    var entity = delegateCrm.AliasedValue(url);
    return new EntityWrapper(entity);
}

単純。実際に使用しているメソッドを委任するだけで済みます。

これにより、クラスをモックアウトできるだけでなく、たとえば、次のバージョンのMS DynamicsでAPIがわずかに変更された場合や、奇妙な動作やパフォーマンスの低下が発生した場合に制御できます。また、APIを実際に使用している部分に絞り込んでいるため、コードの保守がさらに簡単になる場合があります。

コンピューティングには、抽象化の別のレイヤーで解決できないものは何もありません...

于 2012-08-10T16:35:00.043 に答える
0

シールされたクラスをモックするために、非仮想メソッドまたは静的メンバーは、通常、すべての呼び出しをインターセプトできるようにするために、プロファイラー ベースのモック フレームワークが必要です。私が知っている唯一のフレームワークは、それを行うことができ、商用ではありませんMicrosoft Molesです。

Visual Studio 2012 の場合、Moles は Fakes に名前が変更され、インストールに含まれます。Visual Studio 2010 の場合は、別途ダウンロードする必要があります。moles.runner.exeプロファイラー ベースのフレームワークであるため、プロファイラーをセットアップできるように、ランナーでテストを実行する必要があります。

しばらく前に、Moles で NUnit テストを実行するプロセスについて説明したブログ投稿を書きました。次の URL で確認できます。

NUnit と Moles Redux を使用した単体テスト

もう 1 つの方法は、Lunivore の回答の指示に従い、抽象化レイヤーを追加することです。私自身はツールを使ってその問題を解決することを好みますが、Moles を扱うのはそれほど簡単ではないことを事前にお伝えしておく必要があります。TypeMock IsolatorJustMockなどの他のプロファイラー ベースのモック フレームワークは、おそらく使いやすいですが、商用ソリューションです。

于 2012-08-10T16:31:12.800 に答える