2016-10-06 10 views
6

Я пытаюсь написать Системные тесты в NUnit, и я хочу вызвать пользовательский интерфейс с использованием автоматизации пользовательского интерфейса из ms.Как вызвать сеттер для текстового поля WPF в тесте NUnit

По какой-то причине мой Invokes не удается - я нашел несколько подсказок в Интернете, которые привели меня в состояние, где я могу написать компиляционный тест, но мое утверждение не срабатывает.

Вот скомпилированный минимальный пример. Моя проблема - это неудачный тест в этом примере.

Применение 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: Добавлен немного бойлера для ручного тестирования, а также добавлен пользовательский код, который показывает поведение без uiautomation. Это всего лишь побочный фактор, суть которого заключается в этом вопросе.

+2

Надеюсь, вы это уже знаете, но модульные тесты на самом деле не предназначены для тестирования пользовательского интерфейса. Вероятно, он может быть «взломан», чтобы работать, но в конечном итоге вы будете бороться с системой, когда идете. Тестирование пользовательского интерфейса обычно выполняется как часть кодированных пользовательских интерфейсов, а также тестирование с использованием сценариев. –

+0

@BradleyUffner да я знаю :) Это на самом деле так распространено, что вы не можете совершать аутоиммунные игры без попадания на кодированные пользовательские интерфейсы. Я думаю, что Coded UI Tests превосходен, но я хотел немного погрузиться в uiautomation. – 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. [Связывание, скорее всего, будет разрешено в первый раз, когда вызывается метод UpdateLayout в первый раз, если DataContext уже установлен.] (Http: // stackoverflow.com/questions/13875537/when-are-data-bindings) Вторая версия view.Show вызывает событие UpdateLayout. – zzczzc004

2

Фактически вы можете позвонить по телефону TextBox.Text Property.

view.MyTextBox.Text = expected; 

По вашему мнению, вы также привязка к Text собственности на вашей модели представления в то время как вид модели в тесте имеет MyTextBox свойство. Один или другой должен быть обновлен для соответствия.

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

 Смежные вопросы

  • Нет связанных вопросов^_^