Поделиться через


Контрольный запуск

Тестирование запросов/ответов с помощью F#

Джеймс Мак-Кэффри (James McCaffrey)

Код загрузки доступны коллекции кода MSDN
Просмотреть код в интерактивном режиме

Содержание

Тестируемое приложение
XML (веб-службы) Запрос ответ тестирование с F #
Сведения О окружения
Заключение

Язык программирования F # имеет некоторые характеристики, подходит для автоматизации тестирования программного обеспечения. В этом месяце показано, как использовать F # для выполнения запроса ответа HTTP в тестировании XML (веб-службы) веб-приложений. В частности, я создать короткие тестовой программы, имитирует пользователя воспользоваться предоставленным XML (веб-службы) приложения. Окружение F # программно учитывает HTTP запроса о для приложения веб-сервера. Затем выбирается поток ответа HTTP и проверяет HTML-текст ожидаемое значение некий для определения результата успех или сбой. Помимо полезных метод тестирования в свой собственный справа изучение способов выполнения тестирования с F # HTTP запроса ответа предоставляет отличный способ узнать о языка F #. В этом столбце предполагается основные знания XML (веб-службы) технологии и промежуточных программирования навыки с C# или VB.NET, .NET, но у вас есть опыт языка F # не предполагается. Тем не менее даже если вы новичок в XML (веб-службы) и тестирования автоматизации в общем, вы по-прежнему сможете следовать этой колонке без особых сложностей. Чтобы увидеть, где я нахожусь во главе, посмотрите на цифры 1 и 2. На рис. 1 иллюстрирует пример XML (веб-службы) веб-приложения использовать тестируемого. Тестируемая система является простой, но репрезентативный веб-приложением, с именем MiniCalc.

Рисунок 1 XML (веб-службы) веб-приложения В тест

Я намеренно сохранить Мои XML (веб-службы) приложения тестируемого как можно более простыми, чтобы основные положения автоматизации тестирования не скрывать определенную. Реалистичные веб-приложения значительно более сложны чем фиктивный MiniCalc, приложения, показанный на рис. 1, но методики тестирования F # я опишу здесь легко generalize для сложных приложений. MiniCalc веб-приложение принимает два целых числа и инструкции для добавления или умножения. Он затем отправляет значения на веб-сервере, вычисляемые результат. Сервер создает ответ HTML и отправляет его обозревателю клиента где результат отображается четыре десятичных знака. F# тестовой программы показана на рис. 2.

Рисунок 2 тестирование запрос ответ с F #

Моей программы F # называется project.exe и не принимает аргументов командной строки. Для простоты имеется жестко сведения, включая URL-адрес приложения, входные данные тестовых примеров и результатов теста ожидается. Я расскажу позже параметризовать тестовой программы. Моей программы начинается с вывод целевой URL-адрес localhost:15900/MiniCalc/Default.aspx. Обратите внимание, что я использую XML (веб-службы) разработки веб-сервера вместо IIS, поэтому номер порта (15900) указан вместо по умолчанию порт 80. В случае тестирования 001 моей программы F # программно учитывает сведения, которые соответствует пользователя, введите 5 в элемент управления TextBox1, введите 3 в TextBox2, выбор RadioButton1 (для указания операции сложения) и щелкнув Button1 (для вычисления). В фоновом программа фиксирует ответ HTTP веб-сервер и затем ищет ответа для указания, что 8.0000 (правильный результат 5 + 3) в элементе управления TextBox3 результат. Отслеживает окружения случаях число тестов, передачи и номер, сбой (который удивительно интересных операции в F #) и отображает эти результаты после обработки всех тестовых случаев.

В разделах данного столбца, я кратко опишите тестируемого веб-приложения таким образом вы будете знать точно что тестируется. Далее я описывают сведения о создании облегченная автоматизация запрос ответ HTTP, с помощью языка F #. МНЕ подвести, описывая можно изменять методы я представил в соответствии с собственными потребностями. Я также представлю несколько мнений о почему его следует предпринимать время исследовать F #. Я думаю, вы найдете сведения, представленные здесь интересные и полезные дополнение к тестирования набор средств.

Тестируемое приложение

Давайте взглянем на код для MiniCalc XML (веб-службы) веб-приложения, являющийся цель мою автоматизацию тестирования. После создания приложения MiniCalc с помощью XML (веб-службы) 2008 преимущества встроенных разработки веб-сервера. После запуска XML (веб-службы), при нажатии кнопки на файл | создать | веб-узла. Во избежание XML (веб-службы) кода - механизм и сохранить весь код для моего приложения в одном файле, я выбран параметр пустой веб-узел. Чтобы избежать использования IIS, я выбран параметр файловой системы из элемента управления раскрывающегося списка поля размещения. Я решил использовать C# для приложения MiniCalc, но F # тестирования я представлю в этом столбце работает с XML (веб-службы) приложений, написанных в VB.NET. Кроме того с небольшими изменениями программа предназначенных приложения .NET Web, написанные с использованием технологий например классический ASP, CGI, PHP, JSP, Ruby и т. д. Поскольку МНЕ нужно использовать XML (веб-службы) сервере разработки, я согласно стандартное расположение файловой системы, такие как C:\MyWebApps\MiniCalc, а не адрес конкретного IIS такие C:\Inetpub\wwwroot\MiniCalc. При нажатии кнопки OK в диалоговом окне Создать веб-узел для создания структуры моего приложения. Далее я пошло окно обозревателя решений, правой кнопкой мыши на имени проекта MiniCalc и выбрать добавление элемента из контекстного меню. Затем я выбранный веб-формы из списка установленных шаблонов и принимается имя файла Default.aspx. Установлен в "место коде отдельный файл"параметр, а затем выбрать «Добавить».

Далее двойного по имени файла Default.aspx в обозревателе, чтобы изменить код, созданный шаблон. Я удалить весь код шаблона и заменить код, показанный на рис. 3.

На рис. 3 MiniCalc веб-приложения В проверить источник

<%@ Page Language="C#" %>
<script language="C#" runat="server">
  private void Button1_Click(object sender, System.EventArgs e)
  {
    int alpha = int.Parse(TextBox1.Text.Trim());
    int  beta = int.Parse(TextBox2.Text.Trim());

    if (RadioButton1.Checked) {
      TextBox3.Text = Sum(alpha, beta).ToString("F4");
    }
    else if (RadioButton2.Checked) {
      TextBox3.Text = Product(alpha, beta).ToString("F4");
    }
    else
     TextBox3.Text = "Select method";
  }
  private static double Sum(int a, int b) {
    double ans = a + b;
    return ans;
  }
  private static double Product(int a, int b) {
    double ans = a * b;
    return ans;
  }
</script>

<html>
  <head>
    <style type="text/css">
      fieldset { width: 16em }
      body { font-size: 10pt; font-family: Arial }
    </style>
    <title>Default.aspx</title>
  </head>
  <body bgColor="#ffcc99">
    <h3>MiniCalc by ASP.NET</h3>
    <form method="post" name="theForm" id="theForm" 
      runat="server" action="Default.aspx">
      <p><asp:Label id="Label1" runat="server">
        Enter integer:&nbsp&nbsp</asp:Label>
      <asp:TextBox id="TextBox1" width="100" runat="server" /></p>
      <p><asp:Label id="Label2" runat="server">
        Enter another:&nbsp</asp:Label>
      <asp:TextBox id="TextBox2" width="100" runat="server" /></p>
      <p></p>
      <fieldset>
        <legend>Arithmentic Operation</legend>
        <p><asp:RadioButton id="RadioButton1" GroupName="Operation"
          runat="server"/>Addition</p>
        <p><asp:RadioButton id="RadioButton2" GroupName="Operation"
          runat="server"/>Multiplication</p>
        <p></p>
      </fieldset>
      <p><asp:Button id="Button1" runat="server" text=" Calculate "
        onclick="Button1_Click" /> </p>
      <p><asp:TextBox id="TextBox3" width="120" runat="server" /></p>
    </form>
  </body>
</html>

Чтобы сохранить мой исходный код небольшого размера и простых для понимания, не используется хорошо приемы программирования веб-приложения. В частности я не любых ошибок, и я использую подход немного haphazard разработки путем объединения серверных элементов управления (такие как < asp: TextBox >) с помощью обычного HTML (например < полей >). Наиболее важные части кода, список в рис. 3 отметить, используются коды из моей XML (веб-службы) серверных элементов управления. Использовать по умолчанию Label1 идентификаторы (запрос пользователя) TextBox1 и TextBox2 (ввода для двух целых чисел), RadioButton1 и RadioButton2 (Выбор из сложение или умножение) Button1 (вычислить), TextBox3 и (результат). Для выполнения автоматической HTTP запроса ответа тестирования XML (веб-службы) приложения, необходимо знать идентификаторы элементов управления приложения. В этой ситуации имеется исходный код доступен поскольку я создаю приложение себя;но даже если при тестировании веб-приложения, не писал можно всегда проверять приложения с помощью функции источник веб-обозревателе.

Чтобы проверить Мои приложения тестируемого был построен правильно, я нажатия F5 < >ключ. При нажатии кнопки ОК в диалоге результирующий отладка не включена для XML (веб-службы) для изменения файла Web.config веб-приложения. Visual Studio запущена на сервере разработки и назначена произвольного порта веб-приложения — на в этом случае 15900, как можно увидеть в рис 1. Если я хотел указать номер порта, я может выбранный MiniCalc проекта в обозревателе решений щелкнет элемент главного меню Вид и выбран параметр окно свойств. Это будет отображаться «Использовать динамические порты»режим по умолчанию True и я может изменить значение false и ввести значение в «номер порта»поле.

Обратите внимание, что атрибут action < формы >элемент имеет значение Default.aspx. Другими словами каждый раз пользователь отправляет запрос, выполняется одинаковый код страницы Default.aspx. Это дает моего приложения MiniCalc вида отдельное приложение, а не последовательность различных страниц. Поскольку HTTP является протоколом без состояния, ASP.NET выполняет эффект приложения путем сохранения состояния веб-приложения в типе специальное скрытое значение, вызывается событие просмотра состояния. Как мы вскоре увидите дело XML (веб-службы) ViewState приложения является ключом к программным путем учета данных приложения.

XML (веб-службы) Запрос ответ тестирование с F #

Теперь, когда мы рассмотрели тестируемого веб-приложения, давайте рассмотрите F # тестового окружения программы, произведенных снимке экрана на рис. 2. F # под вопросом планируется поставляются с следующей версии XML (веб-службы). В этой статье я решил использовать сентябрь 2008 г. Предварительная технической Просмотр ВЕРСИЯ (Community) версии F # и XML (веб-службы) 2008. По времени чтения данной статьи возможно, другие параметры F #. В любой случае версия CTP, я использовал была чрезвычайно стабильными и установлены без любой сложности. Процесс установки F # размещает все необходимое для написания программ F # в XML (веб-службы).

Начал запустив XML (веб-службы) и выбрав файл | создать | проект. В диалоговом окне Создать проект ЛИ выбранный тип проекта F #, а затем выбран данный шаблон приложения F # для создания командной строки приложения. Именем проекта, "Проект". Имя проекта становится именем полученный исполняемый файл (здесь, project.exe), поэтому более описательное имя, например запрос ответ программы, возможно, были предпочтительнее. После указания расположения Мой проект на F # и нажать кнопку OK, я двойного файл Program.fs в решении XML (веб-службы) окно обозревателя, чтобы открыть окно редактирования. Общая структура моей программы F # присутствует в рис. 4.

Структура программы F # тестов на рис. 4

#light
open System
open System.Text
open System.Net
open System.IO
open System.Web

printfn "\nBegin F# HTTP request-response test of MiniCalc Web App\n"
let url = "http://localhost:15900/MiniCalc/Default.aspx"
printfn "URL under test = %s \n" url

// define function to get ViewState & EventValidation
// set up test case data
try
  // set numPass & numFail counters to 0
  // iterate and process each test case
  // display number pass & number fail
  printfn "\nEnd F# test run"
  Console.ReadLine() |> ignore
with
  | :? System.OverflowException as e ->
    printfn "Fatal overflow exception %s" e.Message
    Console.ReadLine() |> ignore
  | :? System.Exception as e ->
    printfn "Fatal: %s" e.Message
    Console.ReadLine() |> ignore

// end source

В первой строке Мой F # исходного кода, # Light, сообщает компилятору F # использовать упрощенный синтаксис, где отступ и новых строк в части определить структуру программы. Это принято программы на F #. Я использую F # открытые ключевое слово для перенести соответствующего пространства имен .NET в области, аналогично использованию ключевого слова в C# или ключевое слово imports в Visual Basic. Обратите внимание, что поскольку я использую светло-синтаксис, я не используют конца явные инструкции например символ точки с запятой, используемых C#, JavaScript и другими языками, относящиеся к C. Я открытия System.Text, чтобы легко использовать класс кодировки для преобразования текста в байтах. Пространства имен System.NET и System.IO разместить основные классы, необходимые для программной отправки данных на веб-приложения. Пространство имен System.Web не видима по умолчанию к приложению F #, поэтому явно добавленные пространства имен, щелкнув имя проекта в Visual Studio и выбрав параметр «Добавление ссылки». Я открыть System.Web таким образом, класс HttpUtility можно использовать для выполнения Кодировка URL. Мои следующая инструкция выполняется просто:

printfn "\nBegin F# HTTP request-response test of MiniCalc Web App\n"

Функция библиотеки printfn() отображает сведения командной оболочки, как и ожидалось. Строки в F # разделяются двойные кавычки и может содержать внедренные escape-последовательностями такими как \n новой строки. Одной из ключевых характеристик F # является практически все связано вокруг функции, и большинство функций возвращают значение, необходимо явно обработаны. Однако функция printfn() не возвращает значение. Далее я установил Мой целевой URL-адрес:

let url = "http://localhost:15900/MiniCalc/Default.aspx"

Использовать ключевое слово let и =-оператор для привязки значение строки идентификатора с именем URL-адрес. (Многие члены группы F # предпочтительнее использовать символ термин вместо идентификатора.) Обратите внимание, номер порта в строку URL. В этом случае я не следует указывать тип данных для идентификатора url приходится компилятора F # будет вывести тип. Может явно введенный идентификатор url как строку:

let url : string = " . . . "

Вместо жесткого кодирования URL-адрес в источнике F #, МНЕ удалось выборки командной строки аргумента, используя встроенный массив Sys.argv:

let url = Sys.argv.[1]

Sys.argv.[0] — это имя программы-[1] — первый аргумент и так далее. Далее я echo целевой URL-адрес:

printfn "URL under test = %s \n" url

Функция printfn() использует стиль языка, форматирование, где %s указывает строку. Другие распространенные спецификаторы включают %d целое число, %x шестнадцатеричное %.2f с плавающей запятой с двумя десятичными знаками и универсального %A для всех типов. F # поддерживает обработку исключений с помощью конструкции try. Если исключение возникло в блоке try, элемент управления будут переданы блок обработки исключения. Заметьте, что светло-синтаксис, не используйте фигурные скобки, чтобы определить приступить, а конечные точки для кода блока. Вместо этого все инструкции, отступ же число пустых пробелов (нельзя использовать знаки табуляции) являются частью того же блока кода. Последняя строка в моей блока try, вызов ReadLine(), поэтому моей программы будет приостановить выполнение и удерживайте командной оболочки на экране:

Console.ReadLine() |> ignore 

ReadLine() возвращает строку, в F # возвращаемое значение должно быть учтен и компилятор создаст ошибку. Здесь я использую | >оператор канала для передачи возвращаемого значения встроенных ignore объект. В качестве альтернативы для прекращения возвращаемое значение в большинстве случаев можно использовать идентификатор специальные _ (символ подчеркивания) следующим образом:

let _ = Console.ReadLine()

Однако в целях слабая F # синтаксис такой подход не работает как последний оператор блок кода. Мой код обработки исключений используется интересных конструкции F #:

| :? System.OverflowException as e ->
    printfn "Fatal overflow exception %s" e.Message
| :? System.Exception as e ->
    printfn "Fatal: %s" e.Message

Интерпретировать в первой части этого кода означает «Если исключения соответствует типу System.OverflowException, затем назначить идентификатор с именем e исключения и распечатайте строковое сообщение, включающее исключения текст сообщения." | Маркер — это оператор совпадения. Другими словами Если исключение, программа пытается сопоставить исключения с двумя шаблонами. :? тесты оператор для типов, а не значения.

Сведения О окружения

Теперь, когда я объяснил общая структура моей F # тестирования, давайте взглянем на данные. При ссылке на рис. 4 вы увидите, я определяю функцию, которая извлекает сведения о ViewState и EventValidation из тестируемого приложения MiniCalc. В F # перед вызовом их необходимо определить функции в исходном коде. Как я описал выше, поскольку HTTP является протоколом без состояния, XML (веб-службы) использует специальное значение ViewState для поддержания состояния. Значение ViewState строка Base64-кодировке, представляющий состояние XML (веб-службы) веб-приложения после каждого запроса ответа обращение. Значение EventValidation напоминающий значение ViewState, но используется в целях безопасности для предотвращения атак вставки сценария. Как оказалось, если требуется программно учет XML (веб-службы) веб-приложения, необходимо отправить приложения текущее значение ViewState и текущее значение EventValidation. Код для функции, извлекает значения ViewState и EventValidation присутствует в рис. 5.

На рис. 5 функции для выборки ViewState и EventValidation

let getVSandEV (url : string) =
  let wc = new WebClient()
  let st = wc.OpenRead(url)
  let sr = new StreamReader(st)
  let res = sr.ReadToEnd()
  sr.Close()
  st.Close()

  let startI = res.IndexOf("id=\"__VIEWSTATE\"", 0) + 24 
  let endI = res.IndexOf("\"", startI)
  let viewState = res.Substring(startI, endI - startI)

  let startI = res.IndexOf("id=\"__EVENTVALIDATION\"", 0) + 30 
  let endI = res.IndexOf("\"", startI)
  let eventValidation = res.Substring(startI, endI - startI)
  (viewState, eventValidation)

Обратите внимание, использовать ключевое слово let и =-оператор определяется функция F #. Я имя getVSandEV моей функции и укажите один входной параметр с именем url, который имеет строковый тип. Мои подпись функции явно не указывает возвращаемый тип, но я мог сделать так, как я сейчас объясню. Моя функция начинается с создания экземпляра объекта WebClient:

let wc = new WebClient()

Поскольку я поместил оператор открыть пространство имен System.NET, содержит класс WebClient, я полного уточнения имени класса не требуется. Далее я отправить запрос priming конечный URL-адрес:

let st = wc.OpenRead(url)
let sr = new StreamReader(st)
let res = sr.ReadToEnd()

Я использую метод OpenRead(), вместе с StreamReader объект и его метод ReadToEnd() отправляет запрос на целевой веб-приложения и захватить всего исходного кода HTML ответ как строку привязки результата к идентификатор с именем res. В большинстве случаев рекомендуется явно ввести F # идентификаторы, такие как let res: Строка = sr.ReadToEnd(), но в этой ситуации я позвольте компилятору F # вывести тип идентификатора res. На этом этапе необходимо проанализировать ожидания значения ViewState и EventValidation строковое значение, связанный с идентификатором res. Напоминает часть привязан к res строковое значение, имеет значение ViewState:

<input type="hidden" name="__VIEWSTATE"
 id="__VIEWSTATE" value="/wEPDwUK . . . Zmv==" />

Во-первых МНЕ найти расположение начала значения ViewState, с помощью метода String.IndexOf():

let startI = res.IndexOf("id=\"__VIEWSTATE\"", 0) + 24 

Аргумент означает начало поиска res индексом 0 поместите 0, начала строки ответа. Обратите внимание, что поскольку Мой целевая строка содержит двойные кавычки, я разделения целевой строки с помощью \»escape-последовательность. После найти начинается Мой целевое значение фактическое значение ViewState начинается 24 символов из индекса. Обратите внимание, что "— VIEWSTATE"имеет два ведущих символов подчеркивания, не только один. Это довольно грубый способ разбора начального значения ViewState и делает мой код тонкой. Однако в этой ситуации я выполнения автоматизации тестирования легко и быстро и готов принять возможность, что мой код может прервать. Теперь найти место res, где заканчивается значение ViewState:

let endI = res.IndexOf("\"", startI)

Найти первое вхождение любой символ двойной кавычки после начала значения ViewState просто найти (на startI) и привязки, расположение с идентификатором endI. Теперь, когда МНЕ известно, где значение ViewState начинается и заканчивается в res строка ответа, я можно извлечь значение с помощью метода SubString:

let viewState = res.Substring(startI, endI - startI)

Два аргумента метода SubString() являются индекс res начинается извлечение из и числом символов для извлечения (не индекс для завершения извлечения, являющийся распространенные ошибки). Как всегда с индексирования методов вы получили быть очень осторожным во избежание начала или окончания на один знак слишком рано или поздно. Состояния отображения идентификатора теперь содержит начальное значение ViewState для конечного приложения ASP.NET. Извлечение значения EventValidation происходит по той же схеме:

let startI = res.IndexOf("id=\"__EVENTVALIDATION\"", 0) + 30 
let endI = res.IndexOf("\"", startI)
let eventValidation = res.Substring(startI, endI - startI)

Заметьте, что я использовать идентификаторы моего startI и endI, а привязать их новых значений. Это в F #, когда код находится внутри определения метода, что он является допустимым, но не допустимых в кода верхнего уровня за пределами метода. На этом этапе возникают Мой двух значений, привязанных к идентификаторы ViewState и EventValidation. Эффективный возврат значения и одновременно я использую полезные функции F #:

(viewState, eventValidation)

Я не следует использовать ключевое явного возврата;в последней строке функции F # автоматически представляет возвращаемое значение. Здесь я использую круглые скобки для формирования F # кортеж, который можно представить как набор значений. Как упоминалось выше, МНЕ удалось определены моя функция getVSandEV() способом, который явно указывает возвращаемое значение:

let getVSandEV (url : string) : (string * string) = . . .

(Строка * строка) нотации означает, что моя функция возвращает кортеж из двух строк. Теперь, когда я определил моя вспомогательная функция, я настроил данные тестовых примеров:

let testCases =
  [| "001,TextBox1=5&TextBox2=3&Operation=RadioButton1" +
     "&Button1=clicked,value=\"8.0000\",Add 5 and 3"
     "002,TextBox1=5&TextBox2=3&Operation=RadioButton2" +
     "&Button1=clicked,value=\"15.0000\",Multiply 5 and 3"
     "003,TextBox1=0&TextBox2=0&Operation=RadioButton1" +
     "&Button1=clicked,value=\"0.0000\",Add 0 and 0"
  |]

Здесь я создаю неизменяемыми F # массив с именем testCases, содержащий три строки. |. . . Нотация |] используется F # для разделения массив. Поскольку мой три строки являются довольно длинный, я разбить каждую строку на две части и использовать + оператор сцепления строк на соединение нескольких их обратно вместе. F # также принимает ^ знаков для объединения строк. Первая часть первой строки в массив testCases 001, является идентификатором тестовый случай Разделитель запятая, я после TextBox1 = 5 & TextBoxt2 = 3, при разноске MiniCalc веб-приложения будет имитации пользователя, введите эти значения. Третья пара имя значение (операция = RadioButton1) является способом имитации пользователя, выбрав элемент управления RadioButton — в данном случае RadioButton, соответствующий сложения. Вы могли догадаться неправильно (как я первоначально сделал) на наподобие RadioButton1 = проверка. Однако RadioButton1 представляет собой значение элемента управления операции не элемент управления сам. Четвертая пара имя значение (Button1 = нажата), отчасти ввести в заблуждение. Необходимо предоставить значение для Button1 для имитации была нажата пользователем, но подойдет любое значение. Таким образом, я мог бы использовать "Button1 = yadda"или даже просто "Button1 ="Если я хотел. Но "Button1 = нажата кнопка"является более понятными. Следующее поле (значение = "8.0000") в моем случае тестовых данных является значением ожидаемого в форме Строка, я взгляну в ответный поток HTML. Окончательный поле (установка 5 и 3) является простой комментарий.

Использование массива F # для хранения моих данных тестовых примеров возможно простой подход, но существует несколько альтернативных вариантов. МНЕ удалось заменили [|. . . разделители |] с обычного квадратные скобки, например: позволить testCases = ["001. . ." Создание списка F #. Списки являются общие и тематической с старых функциональные языки программирования таких как LISP и пролог, но в этом случае я бы получить не воспользоваться с помощью списка. Кроме того я мог бы создать F # изменяемым массива следующим образом:

let testCases = Array.create 3 ""
testCases.[0] <- "001,. . ."
testCases.[1] <- "002,. . ."
testCases.[2] <- "003,. . ."

Использование изменяемым массивы довольно редко в F #, и снова, я бы получить не преимущество одним здесь;Упомянуть вероятность главным образом, чтобы показать синтаксис изменяемым массива. Можно обращаться к общая структура программы тестирования теста, показано на рис. 3, можно увидеть, я теперь готов начать обработку каждого тестового случая. Начните Настройка счетчика идентификаторы для хранения количества тестовых примеров, передачи и сбой:

let numPass = ref 0
let numFail = ref 0

В большинстве случаев, я бы просто связать эти идентификаторы 0, например, «позволить numPass = 0 ". Однако необходимо инициализировать счетчики за пределами функции и увеличения каждый счетчик внутри функции (как мы рассмотрим чуть ниже), однако печать не конечные значения за пределами функции. В результате небольшие проблемы из-за проблем видимости. В неудобных ситуациях следующим образом одним из подходов является использование ключевое слово ref как я сделал здесь. Я объясню, как работать с идентификаторы ref вскоре. Теперь поставляется trickiest часть синтаксиса Мой F # тестирования. Я обработки каждого тестового случая:

testCases |>
  Seq.iter(fun (testCase : string) ->
  // parse current test case
  // get ViewState and EventValidation
  // send HTTP request and get response
  // check response for expected value
  // print pass or fail
  )

Использовать | >оператор канала для отправки моей массива testCases в метод Seq.iter(), который будет обрабатывать каждого тестового случая элемента в массиве. Seq.iter() ожидает аргумент, который является функцией, которая будет применяться ко всем элементам в последовательности. Я может явно написать функцию, но тематической подход F # — определить анонимная функция на ходу, с помощью "веселый"Ключевое слово. Мои анонимный функция принимает один строковый параметр, с именем testCase, который будет привязан каждый элемент в свою очередь в массиве testCases. Здесь testCase параметр должен быть строкового типа, так как каждый элемент массива testCases является строкой, пропустить я может явную типизацию testCase. Внутри моей анонимная функция ЛИ синтаксический анализ значения текущего теста:

let delimits = [|',';'~'|];
let tokens = testCase.Split(delimits)
let caseID = tokens.[0]
let input = tokens.[1]
let expected = tokens.[2]
let comment = tokens.[3]

Обратите внимание, использовать F # [|. . |] синтаксису разделитель точка с запятой, укажите массива знаков в качестве аргумента для метода String.Split(). Далее я вызова функции getVSandEV(), определенным ранее:

let (vs, ev) = getVSandEV url 

Вспомните, getVSandEV() принимает один строковый аргумент и возвращает кортеж из двух строк. Я использую круглые скобки для записи в наборе, deconstruct значения кортежа и привязать их к идентификаторы vs и ev. Обратите внимание, что в F #, МНЕ необходимо использовать скобки при вызове функции программы. Затем построить Мой фактических данных POST:

let data = input +
 "&__VIEWSTATE=" + HttpUtility.UrlEncode(vs) +
 "&__EVENTVALIDATION=" + HttpUtility.UrlEncode(ev)
let buffer = Encoding.ASCII.GetBytes(data)

Получить значение привязка ввода идентификатора и объединять необходимые значения ViewState и EventValidation. Поскольку значения ViewState и EventValidation в кодировке Base64, они могут содержать знаки, которые не допускается в запроса HTTP POST (в частности, = заполнения знаков), я использовать метод UrlEncode() в пространстве имен System.Web для преобразования таких проблемных знаков в escape-последовательность, например % 3D. Я использую метод GetBytes() преобразовать Мой строку в массив байтов. Теперь я могу создать объект запроса HTTP:

let req = WebRequest.Create(url) :?> HttpWebRequest
req.Method <- "POST"
req.ContentType <- "application/x-www-form-urlencoded"
req.ContentLength <- int64 buffer.Length

Я создаю объект HttpWebRequest, с помощью механизма фабрики класса WebRequest. Я нужно привести возвращаемое значение метода Create(), поэтому использовать опускаться:? >оператор воспринимать означает "и приведение вводе xxx". За изменяемые свойства Мой объекта .NET использовать <-оператор присвоения значения "POST", "приложения и x-www форма urlencoded" и buffer.Length метод ContentType и ContentLength свойствам объекта запроса. Обратите внимание, для приведения свойство Length идентификатор буфера как int64 использовать синтаксис аналогичен языков на основе языка C, а не с помощью:? >оператор. В F # используется синтаксис приведения стиле с типами значений .NET, такие как int64 и:? >со ссылочными типами, например HttpWebRequest. С помощью созданного объекта запроса я могут срабатывать его тестируемого в веб-приложение:

let reqSt = req.GetRequestStream()
reqSt.Write(buffer, 0, buffer.Length)
reqSt.Flush()
reqSt.Close()

Метод Write() фактически не записывает его аргумент массива байтов, я явным образом вызывать метод Flush(), чтобы сделать. Теперь можно получить ответ HTTP и связать его с идентификатором, именем html:

let res = req.GetResponse() :?> HttpWebResponse
let resSt = res.GetResponseStream()
let sr = new StreamReader(resSt)
let html = sr.ReadToEnd()

В F # при вызове метода .NET, которая принимает только один аргумент, можно опустить скобки в вызове. Однако методы .NET без аргументов, с двумя или более аргументов и вызовы конструктора все требуются круглые скобки. Таким образом группа F # предлагает всегда использовать скобки при вызове методов .NET. Теперь я отображать мой ввода тестовый случай:

printfn "============================"
printfn "Test case: %s" caseID
printfn "Comment  : %s" comment
printfn "Input    : %s" input
printfn "Expected : %s" expected 

И я Проверьте ответ HTML искать ожидаемая строка:

if html.IndexOf(expected) >= 0 then
  printfn "Pass"
  numPass := !numPass + 1
else
  printfn " ** FAIL **"
  numFail := !numFail + 1

Я использую метод String.IndexOf(), возвращается -1, если его строковый аргумент не найден или расположение индекса аргумент, если аргумент найден. Обратите внимание, что в F # Если. . использует затем синтаксис явного затем ключевое слово. Вспомните, я объявлен Мой идентификаторы два счетчика, с помощью ключевого слова ref. Мы увидели, что F # использует = связываемом начальное значение идентификатора и <-оператор обновления изменяемых идентификатор. Этот код показывает, что F # использует: =-оператор изменить значение ссылается на идентификатор. Обратите внимание также, поскольку я работе с объектами ref использовать! оператор разыменования и получить значение, связанное с объект ref. После обработки каждого тестового случая я приостановить нажатия клавиши и задержки выполнения 1 секунды:

let _ = Console.ReadLine()
System.Threading.Thread.Sleep(1000)
) // end anonymous function

Здесь я использую общих идиому F # отменить возвращаемое значение Console.ReadLine(), назначив возврата special_identifier. Вместо этого я может командлету возврата "Игнорировать", как упоминалось ранее. Обратите внимание, что поскольку не удалось открыть пространство имен System.Threading, я должен полные мой вызов метода Thread.Sleep(). После обработки все входные данные тестовых примеров в массив testCase анонимные функции Seq.iter() управление передается в конец окружения F # и распечатать суммарные результаты:

printfn "Number pass = %d" !numPass
printfn "Number fail = %d" !numFail
printfn "\nEnd F# test run"

Теперь все готово для выполнения моей программы. Когда я убедитесь, что веб-сервер разработки Visual Studio работает, я могут выполнять моей программы из командной оболочки как показано на рис. 2.

Заключение

Окружение примере F #, я представленных здесь следует дают сплошной базового для создания тестовой программы, выполняющие собственные конкретной ситуации тестирования. В общем случае самых трудных проблемы, будет лицевой стороной является определение данных для отправки веб-приложения в группе проверки. Один хороший способ сделать это является вручную упражнение веб-приложения и записи данных запроса HTTP с помощью средства средство прослушивания, чтобы увидеть, какие сведения отсылаются к веб-серверу, на котором размещается приложение. Доступны такие средства в Интернете как бесплатная загрузка.

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

Подтверждение: Мои благодаря Нг Тим, старший разработки привести группы F #, предустановленным гораздо технические рекомендации для этой статьи.

Отправляйте Джеймсу свои вопросы и комментарии по адресу testrun@microsoft.com

Доктор. Джеймс МакКефри работает в компании компании Information Sciences Inc., где он руководит технической подготовкой Volt программного обеспечения в корпорации Майкрософт Редмонд, Вашингтон кампуса. Он работал над несколькими продуктами корпорации, включая Internet Explorer и MSN Search. Джеймс является автором рецепты автоматизации тестирования .NET (Apress, 2006) . Джеймс может быть достигнут jmccaffrey@volt.com или v-jammc@microsoft.com .