为什么我的Silverlight XAML绑定的unit testing失败了?

我已经定义了以下combobox:

  

其中IsoCurrenciesListIEnumerable – 我们定义的类型,在视图模型中声明为:

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

我的unit testing创​​建了一个视图和视图模型的实例,并在本地列表中设置了一些虚拟货币数据:

 [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 { ukp, usd, eur }; GetUIElement("LayoutRoot").DataContext = _viewModel; } private T GetUIElement(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("cmbCurrency"); // This assert fails as Items.Count == 0 CollectionAssert.AreEquivalent(currencyCombo.Items, _currencies, "Failed to data-bind currencies."); EnqueueTestComplete(); }; TestPanel.Children.Add(_target); } 

我遵循了关于Jeremy Likeness博客的指南,但我无法通过绑定测试。

我已经尝试过测试其他属性的绑定 – 简单的字符串,布尔值和整数,但是在任何一端所做的更改都没有反映到另一个。

我唯一能想到的是,在将视图添加到TestPanel以“激活”绑定后,我需要做另一个步骤,但我不知道它可能是什么。

UPDATE

我应该指出代码在实际应用程序中工作正常。 根据评论(特别是来自Adam Sills的评论),看起来问题在于我没有发布的代码 – 也就是说,这是我们构建XAML的方式,或者我们设置DataContext的方式有所不同。 至少我可以把精力集中在(希望)正确的领域。

看来控件在视图中的位置很重要。 页面XAML是这样的:

   ...    ... The page definition including sub grids, stack panels and the combo box I'm testing along with other controls     

BusyIndicator是Silverlight Toolkit中的一个, SaveConfirmation是我们编写的控件。

如果我测试IsBusy上的IsBusy绑定是否按预期工作。 但是,如果我测试SavedState上的SavedState绑定失败 – 我在测试VendorSaved属性设置为true,但是当我得到控件时绑定值为false。

 var busyIndicator = GetUIElement("activityControl"); Assert.AreEqual(busyIndicator.IsBusy, _viewModel.IsBusy, "Failed to data-bind busy indicator."); var saveConfirmation = GetUIElement("saveConfirmation"); Assert.AreEqual(saveConfirmation.SavedState, _viewModel.VendorSaved, "Failed to data-bind saved state"); 

所以第一次测试通过,但第二次测试失败。

我需要做些什么来确保树中所有元素的绑定都已设置好?

您已为您的ComboBox添加了XAML,但未包含页面的其余部分。 在您的测试中,您有GetUIElement("LayoutRoot").DataContext = _viewModel; 。 在您关注的示例中,他定义:

  

然后他正在测试绑定的控件直接嵌套在该网格中。 您的页面设置方式是否相同?

我的猜测是因为你正在做_viewModel.IsoCurrenciesList = _currencies; 在Loaded处理程序中,而不是像博客中的示例那样填充现有的ObservableCollection属性。 在Dispatcher上的当前调用完成之后,绑定可能不会更新。 虽然我对Silverlight不太熟悉,但肯定会这么说。

要对此进行测试,可以在将_viewModel.IsoCurrenciesList设置为控件上的DataContext之前尝试设置_viewModel.IsoCurrenciesList

感谢Joel C和Adam Sills,我有这个工作。

线索是,在示例中,正在测试的控件是LayoutRoot直接子LayoutRoot ,实际上当我在页面上测试这些控件时,这些测试也通过了。

所以我有两个解决方案:

1)更改测试触发的事件:

 [TestMethod] [Description("Tests that the currency ComboBox is databound correctly")] public void TestCurrencySelection() { _target.LayoutUpdated += (s, e) => { SetupViewModel(); var currencyCombo = GetUIElement("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事件。 这意味着我必须为每个容器元素添加名称,但它确实意味着我可以更逻辑地拆分测试。