11

Microsoft Team System が提供するテスト スーツを使用して、WPF データバインディングを単体テストしようとしています。私のテストのほとんどはユーザーコントロール用であり、実際にはウィンドウ上ではないため、ウィンドウを表示せずにバインディングをテストできるようにしたいと考えています。これは可能ですか、それともより良い方法がありますか? 以下のコードは、ウィンドウを表示すると機能しますが、表示しないとバインディングが更新されません。

            Window1_Accessor target = new Window1_Accessor();
            UnitTestingWPF.Window1_Accessor.Person p = new UnitTestingWPF.Window1_Accessor.Person() { FirstName = "Shane" };
            Window1 window = (target.Target as Window1);
            window.DataContext = p;         
            //window.Show(); //Only Works when I actually show the window
            //Is it possible to manually update the binding here, maybe?  Is there a better way?
            Assert.AreEqual("Shane", target.textBoxFirstName.Text);  //Fails if I don't Show() the window because the bindings aren't updated
4

5 に答える 5

7

WPF バインディング エラーを例外に変換するソリューションを探しているときに、ユニット テスト プロジェクトでも使用できることがわかりました。

テクニックは非常に簡単です:

  1. TraceListenerロギングの代わりにスローするaを導出する
  2. そのリスナーをに追加しますPresentationTraceSources.DataBindingSource

GitHub で完全なソリューションを参照してください。単体テスト プロジェクトが含まれています。

Visual Studio でのテストに失敗しました

于 2013-10-26T18:45:10.113 に答える
2

シェーン、あなたが本当に心配しているのはバインディングが静かに壊れていることである場合は、バインディング トレースをどこか調べられる場所にリダイレクトすることを検討する必要があります。ここから始めます:

http://blogs.msdn.com/mikehillberg/archive/2006/09/14/WpfTraceSources.aspx

それ以外は、バインディングは単体テストの良い候補ではないというギシュに同意します。これは主に、ギシュが「エピローグ」で言及したオートマジックが進行しているためです。代わりに、基礎となるクラスが正しく動作することを確認することに集中してください。

また、PresentationTraceSources クラスを使用すると、さらに堅牢なトレースを取得できることにも注意してください。

http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.aspx

それが役立つことを願っています!

于 2008-12-03T15:17:45.940 に答える
2

それを目玉。
この種の宣言型マークアップはめったに壊れません..誰かが手動でそれを台無しにしない限り.. その場合でも、数分以内に修正できます。私見ですが、そのようなテストを作成するコストは、メリットをはるかに上回ります。

更新[2008 年 12 月 3 日]: わかりました。
このテストは、バインディングの Path プロパティとしてテキスト ボックスの値が "FirstName" であることをテストするだけです。実際のデータ ソース オブジェクトで FirstName を JustName に変更/リファクタリングしても、匿名型に対してテストしているため、テストは成功します。(コードが壊れた場合のグリーン テスト - TDD アンチパターン: 嘘つき) FirstName が XAML で指定されていることを確認することが目的の場合は、

Assert.AreEqual("FirstName", txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).ParentBinding.Path.Path);

単体テストを介して壊れたバインディングを本当にキャッチする必要がある (そして UI を表示したくない) 場合は、実際のデータ ソースを使用してください...しばらく苦労して、これを思いつきました。

[Test]
public void TestTextBoxBinding()
{
   MyWindow w = new MyWindow();
   TextBox txtBoxToProbe = w.TextBox1;
   Object obDataSource = w;               // use 'real' data source 

   BindingExpression bindingExpr = BindingOperations.GetBindingExpression(txtBoxToProbe, TextBox.TextProperty);
   Binding newBind = new Binding(bindingExpr.ParentBinding.Path.Path);
   newBind.Source = obDataSource;
   txtBoxToProbe.SetBinding(TextBox.TextProperty, newBind);

   Assert.AreEqual("Go ahead. Change my value.", txtBoxToProbe.Text);
} 

エピローグ:への呼び出しで実際に秘密のことが起こっていますWindow.Show()。どういうわけか魔法のように DataItem プロパティを設定し、その後データ バインディングが機能し始めます。

// before show
bindingExpr.DataItem => null
bindingExpr.Status => BindingStatus.Unattached

// after show
bindingExpr.DataItem => {Actual Data Source}
bindingExpr.Status => BindingStatus.Active

バインディングがアクティブになったら、次のようなコードを使用してテキストボックスの更新を強制できると思います..

txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).UpdateTarget();

繰り返しますが、私はこのアプローチに抵抗を表明します。NUnit を STA で実行するのは大変でした。

于 2008-12-01T17:58:31.577 に答える
1

いくつかの SO 投稿で出くわしたアドバイスを組み合わせて、WPF バインディングをテストするのに非常にうまく機能する次のクラスを作成しました。

public static class WpfBindingTester
{
    /// <summary>load a view in a hidden window and monitor it for binding errors</summary>
    /// <param name="view">a data-bound view to load and monitor for binding errors</param>
    public static void AssertBindings(object view)
    {
        using (InternalTraceListener listener = new InternalTraceListener())
        {
            ManualResetEventSlim mre = new ManualResetEventSlim(false);

            Window window = new Window
            {
                Width = 0,
                Height = 0,
                WindowStyle = WindowStyle.None,
                ShowInTaskbar = false,
                ShowActivated = false,
                Content = view
            };

            window.Loaded += (_, __) => mre.Set();
            window.Show();

            mre.Wait();

            window.Close();

            Assert.That(listener.ErrorMessages, Is.Empty, listener.ErrorMessages);
        }
    }

    /// <summary>Is the test running in an interactive session. Use with Assume.That(WpfBindingTester.IsAvailable) to make sure tests only run where they're able to</summary>
    public static bool IsAvailable { get { return Environment.UserInteractive && Process.GetCurrentProcess().SessionId != 0; } }


    private class InternalTraceListener : TraceListener
    {
        private readonly StringBuilder _errors = new StringBuilder();
        private readonly SourceLevels _originalLevel;
        public string ErrorMessages { get { return _errors.ToString(); } }

        static InternalTraceListener() { PresentationTraceSources.Refresh(); }

        public InternalTraceListener()
        {
            _originalLevel = PresentationTraceSources.DataBindingSource.Switch.Level;
            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
            PresentationTraceSources.DataBindingSource.Listeners.Add(this);
        }

        public override void Write(string message) {}

        public override void WriteLine(string message) { _errors.AppendLine(message); }

        protected override void Dispose(bool disposing)
        {
            PresentationTraceSources.DataBindingSource.Listeners.Remove(this);
            PresentationTraceSources.DataBindingSource.Switch.Level = _originalLevel;
            base.Dispose(disposing);
        }
    }
}
于 2012-07-13T09:16:50.560 に答える
0

ギアを試すことができます。これを使用すると、UserControl の単体テストを行い、データ バインディングが正しいかどうかを確認できます。ただし、ウィンドウを表示する必要があります。

ここに例があります。UserControl の新しいインスタンスを開始し、その DataContext を設定してから、テキスト ボックスが正しい値に設定されているかどうかを確認します。

    [TestMethod]
    public void SimpleTest()
    {
        var viewModel = new SimpleControlViewModel() {TextBoxText = "Some Text"};

        customControl = CustomControl.Start<SimpleUserControl>((control) => control.DataContext = viewModel);

        Assert.AreEqual("Some Text", customControl.Get<TextBox>("textbox1").Value);

        customControl.Stop();
    }
于 2010-11-04T19:13:35.560 に答える