вторник, 31 октября 2017 г.

Понятные тесты...

Да, опять тесты...

Вот такие тесты сейчас я нахожу очень понятными (в таком формате я и чужие тесты понимаю, и свои многолетней давности):

    [TestFixture]
    public class RibbonFormTests {
        [Test]
        public void RibbonForm_ControlsAddRibbon_SizeSet700x700_Show() {
            using(RibbonForm form = new RibbonForm()) {
                form.Controls.Add(new RibbonControl());
                form.Size = new Size(700, 700);
                form.Show();
                Application.DoEvents();
                Assert.AreEqual(700, form.DesktopBounds.Width);
                Assert.AreEqual(700, form.DesktopBounds.Height);
            }
        }

вторник, 4 июля 2017 г.

Как тестировать расширение поведения контрола?

Например использую я в своем приложении Grid. Лежит он у меня на в одном из окошек. На нем вообще много разных контролов, я закладки сделал и грид у меня на второй закладке. Источник данных для грида у меня умненький: данные загружает только при реальном обращении. Я его сразу в грид присваиваю, код простой получается, а сам грид не пытается сразу же данные зачитывать. И это правильно, ведь закладка-то у него вторая, еще не открытая, и я ожидаю что он не будет загружать данные и увеличивать время для открытия окна. Зато на открытии закладки он сам данные зачитывает, ведь теперь он видимый стал. Очень такой хороший грид. В этом сценарии.

А в соседнем сценарии грид уже не так хорош: если вторую закладку открыть, потом первую закладку, обновить все данные в окне (и сразу же присвоить ему источник данных), то он сразу же зачитает эти данные. Хотя находится на неактивной закладке и его сейчас не видно. Как же быть?

среда, 5 апреля 2017 г.

"Заказчик"/"Product Owner" для вендора компонент?

С этой ролью легко получить разницу с вариантом из Экстремального Программирования: "Заказчик платит - вы делаете" уже не будет соответствовать реальности.

пятница, 3 марта 2017 г.

Как начать планирование релиза?

Попался на глаза этот старый драфт поста, уже несколько лет ждет публикации и все еще выглядит актуальным.
Вот, наконец, дождался....

"Выпуск релиза каждые полгода" и все такое. У этой модели много разных названий, а сама модель работы очень надежная и эффективная. Вот только на каждые полгода ощущается "трение": один релиз уже выпущен, а работа на цели следующего релиза все не начинается и не начинается... Как же так?

Имхо, вполне нормальная ситуация: всегда есть недоделки. Количество недоделок на конкретную дату зависит от "качества" работы в предыдущие полгода. Наделали много долгов - будет много недоделок. Наваяли код, обложили тестами, сделали документацию, наклепали примеров, подготовили презентации, провели тестирование всего этого на "тестовых клиентах", внесли исправления по выявленным проблемам - и долгов будет мало. Трение на старте нового релиза зависит только от этого.
С увеличением размера продукта такое трение становится более разнообразным: 10 человек наделали разное количество долгов и кто-то сидит допоздна каждый день, а кто-то дергает за рукав со словами "ну когда уже релиз планировать будем?" Такая ситуация тоже вполне нормальна и нет смысла откладывать работу только для того, что бы "начать работать над новым релизом одновременно" и именно такой подход мне кажется наилучшим.
Это отличный вариант, но с ним вполне можно "бежать впереди паровоза" и действовать неадекватно "мировой ситуации":
  • В целом по команде не должно быть явных перекосов по долгам, когда у кого-то пусто, а у кого-то полные штаны этих долгов.
  • Установленные критерии качества соблюдаются (ошибки быстро исправляются, вопросы быстро отвечаются).
  • В целом по продукту усилия должны быть приложены по направлениям, которые все признают важными (цели на год-два).

Поэтому я же таким энтузиастам начинаю "вставлять палки в колеса" в соответствии с этими пунктами:
  • "У тебя баги кончились? Фиксить нечего? Вопросы по твоим фичам не задают?"
  • Почему бы тебе вместо нового кода не помочь поправить известные ошибки в новом коде фичи Х? Ах не ты делал... А какая разница? Все равно эти ошибки придется исправлять и чем раньше начнем, тем быстрее получим хорошее качество. Перераспределим ресурсы адекватно реальности.
  • Почему бы тебе вместо твоей идеи "а давайте сделаем Х!" не заняться моей идеей "сделать У"?
  • Вот у нас трафик вопросов большой и специалисты поддержки почти по ночам уже сидят - помоги им раз уж закончил со своей работой по выпущенному релизу. Посмотри почему у них такой завал и как улучшить ситуацию?
К счастью энтузиастов, у меня количество таких палок весьма ограничено и можно заранее подготовиться к попыткам "вставлять их в колеса" и начать таки работать на новый релиз:
  • Да кончились. Да, нет багов. И вопросов тоже нет.
  • Либо фичам готова к выпуску в релизе, либо нет. В новом релизе могу помогать, а сейчас лучше выпилить сырую фичу из релиза.
  • Вон опрос провели и выходит, что нафиг не нужен твой "У", все голосовали за мой "Х". И вопросы я еще посмотрел - то же самое выходит, список вопросов в приложении 1.
  • Вот кто выпустил то, из-за чего специалисты сидят - тот пусть и помогает. Опять же премиями можно мотивировать. А я прошлом релизе начал и закончил так, что никто нигде не засиживается. И могу еще что-нибудь сделать с таким же результатом.
Если есть понятные ответы на эти вопросы, то нет причин откладывать работу. Можно "прям щас" составить план на себя в новом релизе и сразу же начать по нему работать.

"Unit тесты" или "Функциональные тесты"

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

Например, тест из первой группы мог бы проверять результат работы метода, который должен посчитать новое значение в зависимости от переданного значения масштабирования экрана ("Make texts larger" в Windows для HighDpi мониторов): передали в него исходную цифру и несколько масштабов - проверили цифру под каждый масштаб.

А тест из второй группы будет настраивать несколько окружений с разным масштабированием, создавать и показывать форму и проверять размеры и положение контрола в пикселах под каждый вариант масштабирования. Как пример, конечно же.

Что же мне выбрать для эффективной работы?

Зачем автор вписал тут буквы "protected virtual" ?

public partial class MyForm : Form {
  private MyForm() {
   protected virtual void Setup(string caption) {
    ...
  }
  public static void ShowMessage(string caption) {
    MyForm form = new MyForm();
    form.Setup(caption);
    form.ShowDialog();
  }

Зачем автор вписал тут буквы "virtual" ? Ведь этот метод вызывается только из статического метода и никакие "override" в это место не добавить.

Одноглазые тесты

Возникла у меня в приложении проблемка: при смене фильтра в моем гриде пропадало "выделение" строки, т.е. строка есть, ее видно, но она просто не "выделена". А выделение строки очень важно: кнопки Delete/Print и многие другие работают с выделенными записями, т.е. нет выделенных записей - кнопки недоступны.
И в результате поведение моего приложения выглядело ужасно: сменил пользователь фильтр, видит в гриде нужную запись, а удалить ее не может, потому что кнопка Delete недоступна. Кто виноват? Конечно же программист!

Я для этого сценария сделал костылик и написал тест с проверкой выделенных записей в этом сценарии: