2016-10-06 21 views
6

システムテストをNUnitに書き込もうとしていて、msからUIオートメーションを使用してUIを呼び出したいとします。NUnitテストでWPFテキストボックスのセッターを呼び出す方法

何らかの理由で私の呼び出しが失敗しました - 私はコンパイルテストを書くことができますが、私の主張は失敗する状態に私を持っているいくつかのヒントをオンラインで見つけました。

ここにはコンパイル可能な最小の例があります。私の問題は、この例で失敗したテストです。

アプリケーションXAML

<Application x:Class="InvokeTest.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:InvokeTest" 
      Startup="Application_Startup"/> 

アプリケーションCS

using System.Windows; 

namespace InvokeTest 
{ 
    public partial class App : Application 
    { 
     private void Application_Startup(object sender, StartupEventArgs e) 
     { 
      var view = new MainWindow(); 
      var viewmodel = new MainWindowViewModel(); 
      view.DataContext = viewmodel; 
      view.Show(); 
     } 
    } 
} 

ウィンドウXAML

<Window x:Class="InvokeTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:InvokeTest" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
<TextBox x:Name="MyTextBox" x:FieldModifier="public" Text="{Binding TextProperty, UpdateSourceTrigger=PropertyChanged}" /> 
</Window> 

ウィンドウCS

using NUnit.Framework; 
using System.Diagnostics; 
using System.Threading; 
using System.Windows; 
using System.Windows.Automation.Peers; 
using System.Windows.Automation.Provider; 
using System.Windows.Controls; 

namespace InvokeTest 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 
    } 

    public class MainWindowViewModel 
    { 
     string textfield; 
     public string TextProperty 
     { 
      get { DebugLog("getter"); return textfield; } 
      set { textfield = value; DebugLog("setter"); } 
     } 

     private void DebugLog(string function) 
     { 
      Debug.WriteLine(ToString() + " " + nameof(TextProperty) + " " + function + " was called. value: '" + textfield ?? "<null>" + "'"); 
     } 

     [TestFixture, Apartment(ApartmentState.STA)] 
     public class WPFTest 
     { 
      MainWindow view; 
      MainWindowViewModel viewmodel; 

      [SetUp] 
      public void SetUp() 
      { 
       view = new MainWindow(); 
       viewmodel = new MainWindowViewModel(); 
       view.DataContext = viewmodel; 
      } 

      [Test] 
      public void SetTextBox_NoAutomation() 
      { 
       string expected = "I want to set this"; 
       view.MyTextBox.Text = expected; 
       Assert.AreEqual(expected, viewmodel.TextProperty); 
       /* 
       Test Name: SetTextBox_NoAutomation 
       Test Outcome: Failed 
       Result Message: 
       Expected: "I want to set this" 
       But was: null 
       */ 
      } 

      [Test] 
      public void SetTextBox_UIAutomation() 
      { 
       string expected = "I want to set this"; 
       SetValue(view.MyTextBox, expected); 
       Assert.AreEqual(expected, viewmodel.TextProperty); 
       /* 
       Test Name: SetTextBox_UIAutomation 
       Test Outcome: Failed 
       Result Message: 
       Expected: "I want to set this" 
       But was: null 
       */ 
      } 
      private static void SetValue(TextBox textbox, string value) 
      { 
       TextBoxAutomationPeer peer = new TextBoxAutomationPeer(textbox); 
       IValueProvider provider = peer.GetPattern(PatternInterface.Value) as IValueProvider; 
       provider.SetValue(value); 
      } 
     } 
    } 
} 

EDIT#1:@Nkosiは私のxamlにバインディングエラーがあると指摘しました
EDIT#2:手作業によるテストを可能にするボイラーを追加しました。また、自動化なしの動作を示すユースケースを追加しました。それはただの副作用であり、あなたはこの質問の中核です。

+2

これは既に分かっていると思いますが、単体テストは実際にUIをテストするためのものではありません。それはおそらく作業に "ハッキング"することができますが、あなたは行くようにシステムを戦うことになります。 UIテストは、通常、コード化UIテストとスクリプト化された統合テストの一部として実行されます。 –

+0

@BradleyUffnerええええええええええええええええええええええと:)あなたはコード化されたUIテストで打つことなく、あなたがGoogleのオートアイリスをgoogleできないのは実際にはとても一般的です。コード化されたUIテストは優れていると思いますが、私はちょっとした説明に少しでも乗りたいと思っていました。 – Johannes

答えて

0

私はウィンドウを表示する必要があります。 メッセージポンプを稼動させることを前提としています。

誰かがこれに関する詳細を伝えることができれば、その回答を受け入れられた回答として設定します。

using NUnit.Framework; 
using System.Diagnostics; 
using System.Threading; 
using System.Windows; 
using System.Windows.Automation.Peers; 
using System.Windows.Automation.Provider; 
using System.Windows.Controls; 

namespace InvokeTest 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 
    } 

    public class MainWindowViewModel 
    { 
     string textfield; 
     public string TextProperty 
     { 
      get { DebugLog("getter"); return textfield; } 
      set { textfield = value; DebugLog("setter"); } 
     } 

     private void DebugLog(string function) 
     { 
      Debug.WriteLine(ToString() + " " + nameof(TextProperty) + " " + function + " was called. value: '" + textfield ?? "<null>" + "'"); 
     } 

     [TestFixture, Apartment(ApartmentState.STA)] 
     public class WPFTest 
     { 
      MainWindow view; 
      MainWindowViewModel viewmodel; 

      [SetUp] 
      public void SetUp() 
      { 
       view = new MainWindow(); 
       viewmodel = new MainWindowViewModel(); 
       view.DataContext = viewmodel; 
       view.Show(); 
      } 

      [TearDown] 
      public void TearDown() 
      { 
       view.Close(); 
       view.DataContext = null; 
       view = null; 
       viewmodel = null; 
      } 

      [Test] 
      public void SetTextBox_NoAutomation() 
      { 
       string expected = "I want to set this"; 
       view.MyTextBox.Text = expected; 
       Assert.AreEqual(expected, viewmodel.TextProperty); 
      } 

      [Test] 
      public void SetTextBox_UIAutomation() 
      { 
       string expected = "I want to set this"; 
       SetValue(view.MyTextBox, expected); 
       Assert.AreEqual(expected, viewmodel.TextProperty); 
      } 

      private void SetValue(TextBox textbox, string value) 
      { 
       TextBoxAutomationPeer peer = new TextBoxAutomationPeer(textbox); 
       IValueProvider provider = peer.GetPattern(PatternInterface.Value) as IValueProvider; 
       provider.SetValue(value); 
      } 
     } 
    } 
} 
+1

私はバインディングがAttachToContextではないというオリジナルのバージョンだと思います。 [バインディングは、DataContextが既に設定されている場合、UpdateLayoutメソッドが初めて呼び出されたときに初めて解決されます。](http:// stackoverflow。com/questions/13875537/when-are-data-bindings-applied)2番目のバージョンのview.ShowはUpdateLayoutイベントをトリガーします。 – zzczzc004

2

実際にはTextBox.Text Propertyに電話することができます。あなたのビューで

view.MyTextBox.Text = expected; 

テストにおけるビューモデルがMyTextBox性質を有しているあなたも、あなたのビューモデルにTextプロパティにバインドされています。どちらか一方が一致するように更新する必要があります。

public class MainWindowViewModel 
{ 
    public string Text { get; set; } 
} 

[TestFixture, Apartment(ApartmentState.STA)] 
public class WPFTest 
{ 
    [Test] 
    public void SetTextBox() 
    { 
     //Arrange 
     var expected = "I want to set this"; 

     var view = new MainWindow(); 
     var viewmodel = new MainWindowViewModel(); 
     view.DataContext = viewmodel; 

     //Act 
     view.MyTextBox.Text = expected; 

     //Assert 
     Assert.AreEqual(expected, viewmodel.Text); 
    } 
} 
+0

私はバインディングの失敗を提出しました(私は思う:))。あなたの提案は私のマシンでは動作しません - あなたはそれを実行できますか? – Johannes

+0

エラーが生じますか?もしそうなら、彼らは何ですか? – Nkosi

+0

アサーション以外?いいえ。 – Johannes

関連する問題