Фирма

«Инрэко ЛАН»

На сегодняшний день распространена практика разработки программного обеспечения (ПО) через тестирование (Test Driven Development). При таком подходе определяющим фактором является написание как можно более полного набора тестов для разрабатываемого функционала. В итоге, от того, насколько правильным и полным будет этот набор, и зависит качество разрабатываемого ПО. В настоящее время написание тестов для бизнес-логики приложения у большинства разработчиков не вызывает никаких трудностей. С тестированием же пользовательских интерфейсов не всё так однозначно и данный вопрос довольно часто занимает умы как разработчиков, так и отдела тестирования. 

Существует множество фреймворков для написания unit-тестов в среде .NET. С конкретным списком можно ознакомиться по адресу: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#.NET_programming_languages. На мой взгляд, одним из самых популярных и широко используемых является фреймворк NUnit. Изначально NUnit был перенесен из языка Java (фреймворк JUnit), но в дальнейшем был полностью переработан для более эффективного использования возможностей .NET.

NUnitForms является расширением фреймворка NUnit и позволяет делать автоматическое тестирование Windows Forms приложений. Тесты, в данном случае, могут открывать формы и работать с элементами управления, имитируя работу пользователя. Общие сведения, дистрибутивы и документация доступны здесь: http://sourceforge.net/projects/nunitforms. Не вдаваясь в подробности структуры NUnitForms, рассмотрим пример unit-теста для диалогового окна с одним текстовым полем, кнопками «OK» и «Cancel» (Рисунок 1):

Рисунок 1. Тестируемая форма.

В данном случае функционал очень простой: если никакие данные не введены, выводится сообщение «Поле Name не может быть пустым» и форма не закрывается; если же в поле введены данные, то форма закрывается для последующей обработки введенного значения без каких-либо сообщений. Здесь очевидны два тестовых сценария: один — для проверки случая, когда данные не введены, второй — когда в поле формы введены данные.

Посмотрим, как будет выглядеть код unit-теста для вышеописанного функционала в рамках NUnitForms:

using System.Windows.Forms;
using NUnit.Extensions.Forms;
using NUnit.Framework;

namespace InrecoLan.NUnitForms.Tests
{
[TestFixture]
public class NUnitTest : NUnitFormTest
{
TestForm form;
public override void Setup()
{
base.Setup();
form = new TestForm();
form.Show();
}

[Test]
public void TestNoData()
{
ExpectModal("Message", new ModalFormActivated(TestFormNoDataHandler));
var nameTextbox = new TextBoxTester("txtName");
nameTextbox["Text"] = string.Empty;
Assert.AreEqual(string.Empty, nameTextbox.Text);
var okButton = new ButtonTester("btnOK");
okButton.Click();
Assert.IsFalse(form.DialogResult == DialogResult.OK);
}

[Test]
public void TestData()
{
var nameTextbox = new TextBoxTester("txtName");
nameTextbox["Text"] = "abcdefg";
Assert.AreEqual("abcdefg", nameTextbox.Text);
var okButton = new ButtonTester("btnOK");
okButton.Click();
Assert.IsTrue(form.DialogResult == DialogResult.OK);
}

public void TestFormNoDataHandler()
{
var messageBoxTester = new MessageBoxTester("Message");
if (messageBoxTester != null)
{
messageBoxTester.ClickOk();
}
}
}
}

Примечания/пояснения:

  • обращение к элементам управления осуществляется по именам, к формам — по заголовку;
  • метод Setup() вызывается каждый раз перед запуском очередного теста (метод с атрибутом [Test]);
  • если в процессе выполнения тестового сценария предполагается вызов модальных форм (MessageBox, другие формы, которые вызываются с помощью метода ShowDialog()), то такие вызовы должны обрабатываться особым образом, с применением метода ExceptModal(), параметрами являются заголовок окна и обработчик, в котором прописывается последовательность действий для вызываемого диалогового окна;
  • как видно из листинга, тест для GUI почти не отличается от обычного, многим знакомого, unit-теста в контексте фреймворка NUnit, за исключением следующего: класс теста наследуется от NUnitFormTest, для доступа к элементам управления применяются специальные классы ButtonTester, TextBoxTester, MessageBoxTester.

При использовании методологии TDD удобно иметь инструмент, который позволяет распространить аспекты данного подхода как на бизнес-логику разрабатываемого ПО, так и на GUI, тем самым, покрыв тестами все приложение. Преимущество от использования NUnitForms состоит в том, что он основывается на NUnit, который широко используется в настоящее время. Но есть и недостатки: на сегодняшний день разработка NUnitForms не ведется или на это тратится очень небольшое количество ресурсов. Последняя версия, доступная для скачивания, датирована маем 2006 года, да и та «альфа», что говорит о возможных недоработках и багах.

По моему мнению, написание unit-тестов для GUI следует применять лишь в тех случаях, когда это действительно оправдано, т.к. процесс написания тестовых сценариев довольно трудозатратный (из примера хорошо видно, насколько велик исходный код unit-теста для такой небольшой по функционалу тестовой формы). Например, если заказчик предъявляет высокие требования к элементам ввода информации в систему через GUI и готов потратить дополнительные средства для получения более надёжного, стабильного и качественного ПО.

Метки: .NET | NUnit | NUnitForms | test-driven development | Windows Forms | разработка ПО | тестирование GUI

Добавить комментарий