Почему мой модульный тест привязок Silverlight XAML не выполняется? - PullRequest
3 голосов
/ 02 июня 2011

У меня определен следующий комбинированный список:

<ComboBox x:Name="cmbCurrency" 
          ItemsSource="{Binding IsoCurrenciesList}"
          DisplayMemberPath="Description"
          SelectedValuePath="LocaleID"
          SelectedValue="{Binding CurrencyId, Mode=TwoWay">
</ComboBox>

Где IsoCurrenciesList - это IEnumerable<IsoCurrency> - тип, определенный нами и объявленный в модели представления как:

private IEnumerable<IsoCurrency> isoCurrenciesList;
public IEnumerable<IsoCurrency> IsoCurrenciesList
{
    get { return isoCurrenciesList; }
    set
    {
        isoCurrenciesList = value;
        RaisePropertyChangedEvent("IsoCurrenciesList");
    }
}

Мой модульный тест создает экземпляр модели представления и представления и устанавливает некоторые фиктивные данные валюты в локальном списке:

[TestInitialize]
public void TestInit()
{
    _target = new View();

    _viewModel = new ViewModel();

    var ukp = new IsoCurrency { Code = "GBP", Description = "Pound Sterling", LocaleID = 826 };
    var usd = new IsoCurrency { Code = "USD", Description = "US Dollar", LocaleID = 840 };
    var eur = new IsoCurrency { Code = "EUR", Description = "Euro", LocaleID = 978 };
    _currencies = new List<IsoCurrency> { ukp, usd, eur };

    GetUIElement<Grid>("LayoutRoot").DataContext = _viewModel;
}

private T GetUIElement<T>(string name) where T : UIElement
{
    return (T)_target.FindName(name);
}

Затем вызывается метод теста.Это должно установить валюту ComboBox.Items (через свойство ItemsSource)

[Asynchronous]
[TestMethod]
public void TestCurrencySelection()
{
    _target.Loaded += (s, e) =>
        {
            // Set the currency list explicitly
            _viewModel.IsoCurrenciesList = _currencies;

            var currencyCombo = GetUIElement<ComboBox>("cmbCurrency");
            // This assert fails as Items.Count == 0
            CollectionAssert.AreEquivalent(currencyCombo.Items, _currencies, "Failed to data-bind currencies.");

            EnqueueTestComplete();
        };

    TestPanel.Children.Add(_target);
}

Я следовал рекомендациям по блогу Джереми Ликнесса , но не могу пройти тест на привязкипередать.

Я пытался протестировать привязки других свойств - простых строк, логических и целых чисел, но изменения, сделанные на одном конце, не отражаются на другом.

Единственное, что нужноЯ могу думать о том, что есть еще один шаг, который мне нужно сделать после добавления представления к TestPanel, чтобы «активировать» привязки, но я понятия не имею, что это может быть.

ОБНОВЛЕНИЕ

Следует отметить, что код отлично работает в реальном приложении.Основываясь на комментариях (особенно от Адама Силлса), похоже, что проблема заключается в коде, который я не опубликовал - то есть это что-то в том, как мы структурировали XAML, или есть разница вкак мы установили DataContext.По крайней мере, я могу сосредоточить свои усилия (надеюсь) в правильной области.

Похоже, что позиция элемента управления в представлении имеет значение .Страница XAML выглядит примерно так:

<Grid x:Name="LayoutRoot">
    <VisualStateManager.VisualStateGroups>
        ...
    </VisualStateManager.VisualStateGroups>

    <toolkit:BusyIndicator x:Name="activityControl" 
                           IsBusy="{Binding IsBusy}" 
                           BusyContent="{Binding BusyContent}" >
        <Grid>
            ... The page definition including sub grids, stack panels
                and the combo box I'm testing along with other controls

            <ops:SaveConfirmation Grid.Row="1" Margin="5"
                                  x:Name="saveConfirmation"
                                  SavedState="{Binding VendorSaved, Mode=TwoWay}" />
        </Grid>
    </toolkit:BusyIndicator/>
</Grid>

BusyIndicator - это то, что написано в Silverlight Toolkit, а SaveConfirmation - это элемент управления, который мы написали.

Если я тестируюIsBusy привязка к BusyIndicator, которая работает как положено.Тем не менее, если я проверяю привязку SavedState на SaveConfirmation, что не удается - я устанавливаю для свойства VendorSaved значение true в тесте, но когда я получаю элемент управления, значение привязки равно false.

var busyIndicator = GetUIElement<BusyIndicator>("activityControl");
Assert.AreEqual(busyIndicator.IsBusy, _viewModel.IsBusy, "Failed to data-bind busy indicator.");

var saveConfirmation = GetUIElement<SaveConfirmation>("saveConfirmation");
Assert.AreEqual(saveConfirmation.SavedState, _viewModel.VendorSaved, "Failed to data-bind saved state");

Итак, первый тест пройден, но второй не пройден.

Что мне нужно сделать, чтобы убедиться, что привязки элементов на всем протяжении дерева установлены?

Ответы [ 3 ]

2 голосов
/ 02 июня 2011

Полагаю, это потому, что вы делаете _viewModel.IsoCurrenciesList = _currencies; в обработчике Loaded вместо заполнения существующего свойства ObservableCollection, как в примере из блога. Возможно, что привязка не будет обновлена ​​до тех пор, пока не завершится текущий вызов диспетчера. Хотя я недостаточно знаком с Silverlight, чтобы сказать это наверняка.

Чтобы проверить это, вы можете попробовать установить _viewModel.IsoCurrenciesList перед тем, как установить viewModel в качестве DataContext на вашем элементе управления.

1 голос
/ 03 июня 2011

Благодаря Джоэлу С и Адаму Силсу У меня это работает.

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

Итак, у меня есть два решения:

1) Измените событие, при котором запускаются тесты:

[TestMethod]
[Description("Tests that the currency ComboBox is databound correctly")]
public void TestCurrencySelection()
{
    _target.LayoutUpdated += (s, e) =>
        {
            SetupViewModel();

            var currencyCombo = GetUIElement<ComboBox>("cmbCurrency");
            CollectionAssert.AreEquivalent(currencyCombo.Items,
                                           _currencies,
                                           "Failed to data-bind currencies list.");

            Assert.AreEqual(currencyCombo.SelectedValue,
                            _viewModel.CurrencyId,
                            "Failed to data-bind selected currency.");
        };

    TestPanel.Children.Add(_target);
}

Привязки не инициализируются до тех пор, пока не будет отображено Loaded, но к моменту запуска LayoutUpdated.Сделав это изменение, я теперь могу надежно проверять привязки на любом уровне визуального дерева.

Это было бы нормально, если бы я проверял все привязки на странице в одном тесте - что не очень хорошая практика.

2) Используйте родительский элемент UIElement тестируемого элемента управления вместо LayoutRoot и по-прежнему обрабатывайте событие Loaded.Это означает, что мне нужно добавить имена к каждому из этих элементов контейнера, но это значит, что я могу разделить тесты более логично.

1 голос
/ 02 июня 2011

Вы включили XAML для вашего ComboBox, но не для остальной части своей страницы. В вашем тесте у вас есть GetUIElement<Grid>("LayoutRoot").DataContext = _viewModel;. В следующем примере он определяет:

<Grid x:Uid="LayoutRoot" x:Name="LayoutRoot" Background="White"
    DataContext="{Binding Source={StaticResource VMLocator},Path=Cascadia}">

, а затем элементы управления, на которых он проверяет привязки, вкладываются прямо в эту сетку. Ваша страница настроена так же?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...