Тестирование пользовательского элемента управления, полученного из ComboBox - PullRequest
1 голос
/ 26 января 2009

Я создал элемент управления, полученный из ComboBox, и хочу протестировать его поведение.

Однако в моем модульном тесте он ведет себя не так, как в реальном приложении.

В реальном приложении свойство Combobox.DataSource и .Items синхронизируются - другими словами, когда я изменяю Combobox.DataSource, список .Items немедленно и автоматически обновляется, показывая элемент для каждого элемента DataSource.

В моем тесте я создаю 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 ]

2 голосов
/ 26 января 2009

Поскольку вы просто вызываете конструктор, многие функциональные возможности комбинированного списка не будут работать. Например, элементы будут заполнены, когда ComboBox нарисован на экране, в форме. Этого не происходит при построении в модульном тесте.

Почему вы хотите написать модульный тест для этого списка?

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

Почему бы вам не проверить свойство DataSource вместо коллекции Items?

0 голосов
/ 03 мая 2012

Я сделал небольшой хак, чтобы разрешить это в своем пользовательском комбинированном ящике:

public class EnhancedComboBox : ComboBox 
{

    [... the implementation]

    public void DoRefreshItems()
    {
        SetItemsCore(DataSource as IList);       
    }
}

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

Эта функция никогда не вызывается, когда элемент управления не находится в форме, потому что существует множество проверок для CurrencyManager s и BindingContext s, которые дают сбой, потому что эти компоненты, я полагаю, как-то предоставляются родительской формой .

В любом случае, в тесте вы должны вызвать mECB.DoRefreshItems() сразу после mECB.DataSource = mTestItems, и все будет хорошо, если вы зависите только от свойств SelectedIndex и Items. Любое другое поведение, такое как привязка данных, вероятно, все еще не работает.

0 голосов
/ 31 марта 2009

Это решает некоторые проблемы, если целью является ComboBox или любой другой элемент управления:

target.CreateControl ();

но мне не удалось установить для SelectedValue значение null, мой тест работал с двумя источниками данных для поля со списком: один в качестве источника данных, а второй привязан к выбранному значению. С другими элементами управления все работает нормально. В начале я также создавал форму в тестах, но есть проблема, когда форма создается на нашем сервере сборки во время выполнения тестов.

0 голосов
/ 20 февраля 2009

У меня та же проблема с полем со списком, где элементы привязаны к данным. Мое текущее решение - создать форму в тесте, добавить поле со списком в коллекцию Controls, а затем показать форму в моем тесте. Вроде некрасиво. Все, что на самом деле делает мое поле со списком, - это список объектов TimeSpan, отсортированных и с пользовательским форматированием значений TimeSpan. Он также имеет особое поведение на событиях нажатия клавиш. Я пытался извлечь все данные и логику в отдельный класс, но не смог понять это. Возможно, есть лучшее решение, но то, что я делаю, кажется удовлетворительным.

Чтобы упростить тестирование, я создал следующие классы в своем тестовом коде:

    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);
    }
0 голосов
/ 26 января 2009

Я уверен, что Application.Run отсутствие не может повлиять на поведение любого элемента управления

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