测试从ComboBox派生的自定义控件

时间:2009-01-26 12:09:23

标签: c# .net winforms unit-testing custom-controls

我已经创建了一个从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,在单元测试场景中我实际上不需要绘制框?”

5 个答案:

答案 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函数指示基本组合框使用提供的列表加载内部项,它是数据源更改后内部使用的内容。

当控件不在表单上时,永远不会调用此函数,因为有很多检查失败的CurrencyManagerBindingContext,因为我认为这些组件是由提供的父母的形式不知怎的。

无论如何,在测试中,您必须在mECB.DoRefreshItems()之后致电mECB.DataSource = mTestItems,如果您只依赖于SelectedIndexItems属性,那么一切都应该没问题。像数据绑定这样的任何其他行为可能仍然不起作用。