4

私はコードの到達が困難な部分、特にサイトコア クラス ライブラリ (モッキング フレームワークを使用するのが難しい) で見つかった型を使用する部分で単体テストを作成するためにモルを使用しています。私は、LinkField 型をほくろして、次の種類のコード スニペットをテストしようとしているときに、驚くほどトリッキーな問題に遭遇しました。

LinkField linkField = item.Fields["External Url"];

if (linkField.IsInternal && linkField.TargetItem != null)
{
// want to test this path

item.Fields は、インデクサーが SiteCore.Data.Field の型を返すフィールド コレクションですが、LinkField は、コード内で LinkField のインスタンスを操作できることを意味する変換を隠す暗黙の演算子を使用するように設定されています。

問題は、MLinkField 型のモグラを作成できず、Field に強く型付けされているため、これを Item の FieldCollection に割り当てることができないことです。さらに、MField の型を作成することはできますが、暗黙的な変換が発生すると、それは機能してオブジェクトを返しますが、どのフィールドも値を持つように設定されていないようです。これは、特定の方法で設定されている linkField の状態に依存する上記のコード パスをテストできないことを意味します。

これらの値を設定する唯一の方法は、間接的な方法です。つまり、暗黙的な変換を分析して MField に設定することで、設定する必要がある値を見つけます。暗黙の演算子は、次のように LinkField コンストラクターを呼び出します。

public LinkField(Field innerField) : base(innerField, "link")

つまり、基本型 (XmlField) をインスタンス化する方法と、そのクラスの基本型 (CustomField) をインスタンス化する方法を意識する必要があります。次に、TargetItem が探している基本的な値を確認します。最終結果は、モルアウトする必要があります。

InnerField.Database.Items[internalPath];

または

InnerField.Database.Items[targetID];

InnerField は実質的に私の MField です。

誰かがより良いアイデアを持っていますか? これはひどく複雑に聞こえますが、それがこれらのアセンブリの野獣の性質だと思います。

4

3 に答える 3

3

実行できますが、機能させるにはいくつかの手順を踏む必要があります。

まず、少し背景を説明します。

  • LinkField は、他のフィールド タイプのように Field クラスから継承しません。
  • LinkField は XmlField を継承し、XmlField は CustomField を継承します。
  • CustomField (およびそのサブタイプ) は、フィールド インスタンスをコンストラクターに渡すことによってインスタンス化されます。
  • リンクフィールドは、その値をこのフィールド インスタンスに格納します。
  • Linkfields は Field から継承されないため、FieldCollection に追加できません。
  • LinkField を追加するのではなく、LinkField の InnerField プロパティを追加する必要があります。
  • Field が FieldCollection から取得され、LinkField に割り当てられると、暗黙的な変換操作が実行されます。
  • 暗黙的な変換操作は、選択したフィールドを LinkField のコンストラクターに渡すことによって、新しい LinkField を作成します。返されるのは、この新しい LinkField です。

今いくつかのコード:

const string externalUrl = "External Url";
const string targetItemName = "Target Item";                     
Field field = new ShimField { IDGet = () => ID.NewID, NameGet = () => externalUrl };
Item targetitem = new ShimItem { IDGet = () => ID.NewID, NameGet = () => targetItemName };
LinkField linkfield = new ShimLinkField(field) { IsInternalGet = () => true, TargetItemGet = () => targetitem };                         
ShimLinkField.ImplicitOpFieldLinkField = (f) => linkfield;
FieldCollection fields = new ShimFieldCollection { ItemGetString = (name) => linkfield.InnerField };
Item item = new ShimItem { NameGet = () => "Test Item", FieldsGet = () => fields };

それでは、少し説明します。

上記のコードを機能させるための鍵は、次の行です。

ShimLinkField.ImplicitOpFieldLinkField = (f) => linkfield;

暗黙の変換演算子をシミングすることで、次の行が呼び出されたときに確実に行うことができます。

LinkField linkField = item.Fields["External Url"];  

リンク フィールドが返され、そのプロパティが必要に応じて調整されます。

于 2014-01-14T12:08:11.330 に答える
1

適切な方法でモックできないためLinkField、「そのまま」単体テストで使用する必要があります。つまり、コードとリンク フィールドの実装の両方をテストする必要があります。

幸いなことに、Link フィールドはXmlField、内部フィールド値に格納された xml データを操作する です。リンク フィールドの動作を構成するには、値に適切な xml を設定するだけです。

Sitecore.FakeDbを使用すると、メモリ内にコンテンツを簡単に作成し、必要なアイテムとフィールドを構成できます。次のコードは、項目hometargetを作成します。ホームアイテムには、ターゲットアイテムを指すURLリンク フィールドがあります。TargetId

  ID targetId = ID.NewID;

  using (var db = new Db
    {
      new DbItem("home")
        {
          // Field 'Url' is an internal link which targets the 'target' item
          { "Url", "<link linktype=\"internal\" id=\"{0}\" />".FormatWith(targetId) }
        },
      new DbItem("target", targetId)
    })
  {
    Item item = db.GetItem("/sitecore/content/home");
    LinkField linkField = item.Fields["Url"];

    linkField.IsInternal.Should().BeTrue();
    linkField.TargetItem.Should().NotBeNull();
    linkField.TargetItem.Paths.FullPath.Should().Be("/sitecore/content/target");
  }
于 2015-01-18T13:01:22.683 に答える