Интеграционный тест с использованием Bot Framework и DirectLine (3)

· 4 мин чтения

Это последняя часть руководства, в этой части мы будем оценивать текст из утверждения в json.

Теперь, когда мы использовали request и отправили боту как activity, мы получили response и нам нужно сравнить то, что assert в json (ответ, который мы сохранили в json, это ожидаемый ответ) с ответом, который мы получили от бота.

Следующее объяснение не охватывает всю основную информацию о том, как работает Bot Framework. Если вы не понимаете, пожалуйста, просмотрите официальную документацию.

Добавление Microsoft.CodeAnaанализ в решение

Прежде всего, нам нужно включить CodeAnalysis как пакет NuGet.

[[[[ТОК_4]]])

После установки не забудьте добавить пакет в файл .cs.

[[[ТОК_7]]]

Создание объекта Globals

Чтобы оценить, мы должны передать параметры оценщику. Этому оценщику нужен файл конфигурации.

[[[ТОК_9]]]

Эта часть очень важна: в этот файл конфигурации мы будем включать объекты, которые будем сравнивать, поэтому нам нужно передать ему ожидаемый ответ и полученный ответ.

Имея эту информацию, он будет использовать assert в файле json и оценивать то, что он говорит.

[[[ТОК_11]]]

EvaluateAsync<T> оценивает и возвращает T, в нашем случае мы передаем string для оценки и globals, который содержит данные, в которых он будет оценивать.

Я попытаюсь объяснить это на примере, используя запись (которая имеет имя, запрос, ответ и утверждение).

{
      "name": "DecirHola",
      "request": {
        "type": "message",
        "text": "Hola",
        "from": {
          "id": "default-user",
          "name": "User"
        },
        "locale": "es",
        "textFormat": "plain",
        "timestamp": "2018-04-09T08:04:37.195Z",
        "channelData": {
          "clientActivityId": "1523261059363.6264723268323733.0"
        },
        "entities": [
          {
            "type": "ClientCapabilities",
            "requiresBotState": true,
            "supportsTts": true,
            "supportsListening": true
          }
        ],
        "id": "61hacck8j6jg"
      },
      "response": {
        "type": "message",
        "timestamp": "2018-04-09T08:04:37.901Z",
        "localTimestamp": "2018-04-09T09:04:37+01:00",
        "serviceUrl": "http://localhost:50629",
        "channelId": "emulator",
        "from": {
          "id": "j98bbdf097a",
          "name": "Bot"
        },
        "conversation": {
          "id": "eabcie4be8ak"
        },
        "recipient": {
          "id": "default-user"
        },
        "locale": "es",
        "text": "No tengo respuesta para eso.",
        "attachments": [],
        "entities": [],
        "replyToId": "61hacck8j6jg",
        "id": "47me557ikbf7"
      },
      "assert": "Request.Text == Response.Text"
    }

Давайте возьмем самое важное из этой записи: сначала утверждение "assert": "Request.Text == Response.Text", это означает, что оно сравнит Request.Text с Response.Text и вернет значение в виде логического значения.

Но когда мы вызываем функцию await CSharpScript.EvaluateAsync<bool>(entry.Assert, globals: globals) мы передаем 2 параметра:

  • string строка для оценки -> "Request.Text == Response.Text"
  • Данные globals для оценщика -> в этом случае мы должны предоставить Request и Response, запрос — это наш ожидаемый ответ, а ответ — это полученный ответ.

Поскольку мы заполняем данные в вычислителе, теперь мы можем использовать строку и оценивать, поэтому она вернет true или false.

Готово

Мы закончили, здесь вы можете увидеть готовый TestMethod

[TestMethod]
public async Task ShouldTestSingleCases()
{
    // Load entries from file
    var path = System.IO.File.ReadAllText(@"C:\data.json");

    // Deserialize to object
    var data = JsonConvert.DeserializeObject<TestEntriesCollection>(path);

    /// Flow: Arrange -> Act -> arrange -> assert

    foreach (TestEntry entry in data.Entries)
    {
        /// Arrange with current requested values
        string token, newToken, conversationId;

        if (entry.Request.Type == ActivityTypes.Message)
        {
            /// Act

            /// 1 - Get token using secret from DirectLine in BotFramework panel
            token = Utils.uploadString<DirectLineAuth>(data.Secret, data.DirectLineGenerateTokenEndpoint, "").token;

            /// 2 -Create a new conversation
            var createdConversation = Utils.uploadString<DirectLineAuth>(token, data.DirectLineConversationEndpoint, "");

            // This returns a new token and a conversationId
            newToken = createdConversation.token;
            conversationId = createdConversation.conversationId;

            /// 3 - Send an activity to the conversation with new token and conversationId
            string directlineConversationActivitiesEndpoint = data.DirectLineConversationEndpoint + conversationId + "/activities";
            Utils.uploadString<DirectLineAuth>(newToken, directlineConversationActivitiesEndpoint, JsonConvert.SerializeObject(entry.Request));

            /// 4 - Get all activities, we get a List<activity> and a watermark
            var getLastActivity = Utils.downloadString<ActivityResponse>(newToken, directlineConversationActivitiesEndpoint);

            /// 5 - Get the latest activity which is the response we should be expecting
            var latestResponse = getLastActivity.activities[Int32.Parse(getLastActivity.watermark)];

            /// Arrange with new values
            var globals = new Objects.Globals { Request = entry.Response, Response = latestResponse };

            /// Assert
            Assert.IsTrue(await CSharpScript.EvaluateAsync<bool>(entry.Assert, globals: globals));
        }
    }
    await Task.CompletedTask;
}

Диаграмма

Вот диаграмма всего процесса, которому мы следовали, чтобы понять этот момент. Надеюсь, если вы чего-то не поняли, это прояснит ситуацию.

https://gyazo.com/1e3b7c9c2286844062878b4b8ca02d2d

И это все, это делается для единичных случаев, когда случай 1 к 1, пользователь отправляет activity и бот возвращает еще один одиночный activity.

Надеюсь, вам понравилось. следующим будут сценарии тестирования с более чем одним ответом.

https://gyazo.com/d964cfac395ed438a5282e60614863e7

Помните, что весь код хранится у меня на github в репозитории this.