10

私はこの静的ヘルパー関数を持っています:

    public static DependencyObject GetParentObject(DependencyObject child)
    {
        if (child == null) return null;
        ContentElement contentElement = child as ContentElement;

        if (contentElement != null)
        {
            var parent = ContentOperations.GetParent(contentElement);
            if (parent != null) return parent;

            var fce = contentElement as FrameworkContentElement;
            return fce != null ? fce.Parent : null;
        }

        //if it's not a ContentElement, rely on VisualTreeHelper
        return VisualTreeHelper.GetParent(child);
    }

それは実際のアプリケーションで動作しますが、私はそれのためにいくつかの単体テストを書こうとしています。これが私の最初の試みです:

    [Test]
    public void GetParentObject_returns_immediate_parent()
    {
        var contentControl = new ContentControl();
        var textBox = new TextBox();

        contentControl.BeginInit();
        contentControl.Content = textBox;
        contentControl.EndInit();

        var result = UIHelper.GetParentObject(textBox);
        Assert.AreSame(contentControl, result);
    }

VisualTreeHelper残念ながら、はnullを返すため、失敗します。動作するビジュアルツリーをモックアップするにはどうすればよいですか?

4

3 に答える 3

3

Wpf-controlsを介したドキュメントの印刷とXPSへの変換に関するこの回答に基づいて、ビジュアルツリーを作成するための次の拡張方法を考え出しました。STAスレッドなどがなくてもNUnit内でうまく機能します。

/// <summary>
/// Render a UIElement such that the visual tree is generated, 
/// without actually displaying the UIElement
/// anywhere
/// </summary>
public static void CreateVisualTree(this UIElement element)
{
    var fixedDoc = new FixedDocument();
    var pageContent = new PageContent();
    var fixedPage = new FixedPage();
    fixedPage.Children.Add(element);
    pageContent.ToMaybeOf<IAddChild>().Do(c => c.AddChild(fixedPage));
    fixedDoc.Pages.Add(pageContent);

    var f = new XpsSerializerFactory();
    var w = f.CreateSerializerWriter(new MemoryStream());
    w.Write(fixedDoc);
}

その点に注意してください

  • もう1つの答えは、私が見ているAPIとは異なるReach-dllのAPIを使用しています。.NEtFrameworkバージョン3.5と4.0の間には違いがあると思います
  • ToMaybeOf基本的には、そのインターフェースとして扱い、pageContentアクションIAddChildを実行することを意味します
  • これは、ウィンドウタイプの要素では機能しません。これは、要素が基本的に子としてビジュアルに追加され、ウィンドウがこれについて激しく不平を言うためです。
于 2012-03-01T15:58:08.890 に答える
2

これが静力学が問題となる理由です。

インターフェイスの背後にある機能を抽象化し、静的メソッドを使用するデフォルトの実装を作成できます。次に、依存性注入を使用できます。これにより、この単体テストは簡単になります。IVisualTreeHelperへの依存性をモックするか、割り当てた値を返すように構成できる独自のスタブ実装をロールします。

public class Foo
{
    static IVisualTreeHelper visualTreeHelper;

    static Foo()
    {
        Foo.visualTreeHelper = new FrameworkVisualTreeHelper();
    }

    public Foo(IVisualTreeHelper visualTreeHelper)
    {
        Foo.visualTreeHelper = visualTreeHelper;
    }

    public static DependencyObject GetParentObject(DependencyObject child)
   {
       if (child == null) return null;
       ContentElement contentElement = child as ContentElement;

       if (contentElement != null)
       {
           var parent = ContentOperations.GetParent(contentElement);
           if (parent != null) return parent;

           var fce = contentElement as FrameworkContentElement;
           return fce != null ? fce.Parent : null;
       }

       //if it's not a ContentElement, rely on the IVisualTreeHelper
       return visualTreeHelper.GetParent(child);
   }
}

public interface IVisualTreeHelper
{
    DependencyObject GetParent(DependencyObject reference);
}

public class FrameworkVisualTreeHelper : IVisualTreeHelper
{
    public DependencyObject GetParent(DependencyObject reference)
    {
        return VisualTreeHelper.GetParent(reference);
    }
}

VisualTreeHelper明らかに、他の場所で他のメソッドを使用している場合は、インターフェイスとデフォルトの実装に他のメソッドを追加する必要があるかもしれません。

テストしているユニット自体が静的であるため、まだ完全にはクリーンではありません。UIHelperクラスの静的メソッドに依存するクラスをユニットテストしようとすると、まったく同じ問題が発生します。

于 2010-11-23T14:38:10.880 に答える
-1

ビジュアルツリーをモックするには、実際に作成してレンダリングする必要があります。したがって、実際のウィンドウを作成する必要がありますが、これは単体テストには特に理想的ではありません。

于 2010-11-23T14:22:18.070 に答える