为什么我的Silverlight XAML绑定的unit testing失败了?
我已经定义了以下combobox:
其中IsoCurrenciesList
是IEnumerable
– 我们定义的类型,在视图模型中声明为:
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
。 在您关注的示例中,他定义:
然后他正在测试绑定的控件直接嵌套在该网格中。 您的页面设置方式是否相同?
我的猜测是因为你正在做_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
事件。 这意味着我必须为每个容器元素添加名称,但它确实意味着我可以更逻辑地拆分测试。