我已经创建了一个从ComboBox派生的控件,并希望对其行为进行单元测试。
但是,在我的单元测试中,它在实际应用程序中的行为似乎有所不同。
在实际应用程序中,Combobox.DataSource属性和.Items同步 - 换句话说,当我立即更改Combobox.DataSource .Items列表并自动更新以显示DataSource的每个元素的项目。 / p>
在我的测试中,我构造了一个ComboBox,为它分配了一个数据源,但.Items列表根本没有更新,保留在0项。因此,当我尝试在测试中将.SelectedIndex更新为0以选择第一个项目时,我收到了ArgumentOutOfRangeException。
这是因为我在单元测试中没有Application.Run来启动事件循环,还是有点像红鲱鱼?
编辑:第一次测试的更多细节:
[SetUp]
public void SetUp()
{
mECB = new EnhancedComboBox();
mECB.FormattingEnabled = true;
mECB.Location = new System.Drawing.Point( 45, 4 );
mECB.Name = "cboFind";
mECB.Size = new System.Drawing.Size( 121, 21 );
mECB.TabIndex = 3;
mECB.AddObserver( this );
mTestItems = new List<TestItem>();
mTestItems.Add( new TestItem() { Value = "Billy" } );
mTestItems.Add( new TestItem() { Value = "Bob" } );
mTestItems.Add( new TestItem() { Value = "Blues" } );
mECB.DataSource = mTestItems;
mECB.Reset();
mObservedValue = null;
}
[Test]
public void Test01_UpdateObserver()
{
mECB.SelectedIndex = 0;
Assert.AreEqual( "Billy", mObservedValue.Value );
}
尝试将SelectedIndex设置为0时,测试在第一行失败。在调试时,这似乎是因为更改.DataSource时,.Items集合未更新以反映此情况。但是,在调试实际应用程序时,.Items集合总是在.DataSource更改时更新。
当然,我不必在测试中实际渲染ComboBox,我甚至没有设置任何绘图表面来渲染!也许我需要的唯一答案是“如何在绘制时以与绘制时相同的方式更新ComboBox,在单元测试场景中我实际上不需要绘制框?”
答案 0 :(得分:2)
由于您只是调用构造函数,因此组合框的许多功能都不起作用。例如,当在屏幕上,在表单上绘制ComboBox时,将填充项目。在单元测试中构建它时不会发生这种情况。
为什么要在该组合框上编写单元测试?
你不能分开现在在自定义控件中的逻辑吗?比如把它放在一个控制器中,并测试一下?
为什么不在DataSource属性而不是Items集合上进行测试?
答案 1 :(得分:0)
我确信Application.Run
缺席不会影响任何控件的行为
答案 2 :(得分:0)
我在组合框中遇到了同样的问题,其中项目是数据绑定的。我目前的解决方案是在测试中创建一个Form,将组合框添加到Controls集合中,然后在我的测试中显示该表单。有点难看。我的所有组合框实际上都列出了一堆TimeSpan对象,已排序,并具有TimeSpan值的自定义格式。它还对keypress事件有特殊行为。我尝试将所有数据和逻辑提取到一个单独的类但无法弄清楚。可能有更好的解决方案,但我所做的似乎令人满意。
为了简化测试,我在测试代码中创建了这些类:
class TestCombo : DurationComboBox {
public void SimulateKeyUp(Keys keys) { base.OnKeyUp(new KeyEventArgs(keys)); }
public DataView DataView { get { return DataSource as DataView; } }
public IEnumerable<DataRowView> Rows() { return (DataView as IEnumerable).Cast<DataRowView>(); }
public IEnumerable<int> Minutes() { return Rows().Select(row => (int)row["Minutes"]); }
}
class Target {
public TestCombo Combo { get; private set; }
public Form Form { get; private set; }
public Target() {
Combo = new TestCombo();
Form = new Form();
Form.Controls.Add(Combo);
Form.Show();
}
}
以下是一个示例测试:
[TestMethod()]
public void ConstructorCreatesEmptyList() {
Target t = new Target();
Assert.AreEqual<int>(0, t.Combo.DataView.Count);
Assert.AreEqual<int>(-1, t.Combo.SelectedMinutes);
Assert.IsNull(t.Combo.SelectedItem);
}
答案 3 :(得分:0)
如果target是ComboBox或任何其他控件,这解决了一些问题:
target.CreateControl();
但我无法设置SelectedValue它有空值,我的测试使用两个数据源组合框,一个作为数据源,第二个绑定到selevted值。与其他控件一起工作正常。在开始时我也在测试中创建表单,但是在执行测试时在构建服务器上创建表单时会出现问题。
答案 4 :(得分:0)
我在我的自定义派生组合框中做了一点点修改:
public class EnhancedComboBox : ComboBox
{
[... the implementation]
public void DoRefreshItems()
{
SetItemsCore(DataSource as IList);
}
}
SetItemsCore
函数指示基本组合框使用提供的列表加载内部项,它是数据源更改后内部使用的内容。
当控件不在表单上时,永远不会调用此函数,因为有很多检查失败的CurrencyManager
和BindingContext
,因为我认为这些组件是由提供的父母的形式不知怎的。
无论如何,在测试中,您必须在mECB.DoRefreshItems()
之后致电mECB.DataSource = mTestItems
,如果您只依赖于SelectedIndex
和Items
属性,那么一切都应该没问题。像数据绑定这样的任何其他行为可能仍然不起作用。