Teste de integração usando Bot Framework e DirectLine (3)

· 4 min de leitura

Esta é a última parte do guia, nesta parte estaremos avaliando o texto do assert no json.

Agora que usamos o request e enviamos como um activity para o bot, obtivemos o response e temos que comparar o que o assert no json (a resposta que armazenamos no json, esta é a resposta esperada) com a resposta que obtivemos do bot.

A explicação a seguir não cobrirá todas as informações básicas de como funciona o Bot Framework. Se você não entender, consulte a documentação oficial.

Adicionando Microsoft.CodeAnalysis à solução

Primeiro de tudo, temos que incluir CodeAnalysis como um pacote NuGet.

https://gyazo.com/ce97a60ecab998f162f6ac7a2ab2c9a7

Após a instalação, lembre-se de adicionar o pacote ao arquivo .cs.

using Microsoft.CodeAnalysis.CSharp.Scripting;

Criando um objeto Globals

Para avaliar, temos que passar os parâmetros ao avaliador. Este avaliador precisa de um arquivo de configuração.

 /// <summary>
/// Object to pass parameters to Roslyn compiler
/// </summary>
public class Globals
{
    /// <summary>
    /// ExpectedResponse
    /// </summary>
    public Activity Request;
    /// <summary>
    /// ReceivedResponse
    /// </summary>
    public Activity Response;
}

Essa parte é muito importante, nesse arquivo de configuração estaremos incluindo quais objetos iremos comparar, então para nós precisamos passar a resposta esperada e a resposta recebida.

Com essas informações, ele estará usando o assert no arquivo json e estará avaliando o que está escrito.

/// 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));

O EvaluateAsync<T> avalia e retorna T, no nosso caso passamos o string para avaliar e o globals, que possui os dados onde irá avaliar.

Vou tentar explicar isso com um exemplo, usando uma entrada (que possui nome, solicitação, resposta e afirmação).

{
      "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"
    }

Vamos pegar as coisas importantes desta entrada, primeiro a afirmação "assert": "Request.Text == Response.Text", isso significa que ele irá comparar o Request.Text com o Response.Text e retornar o valor como um booleano.

Mas quando chamamos a função await CSharpScript.EvaluateAsync<bool>(entry.Assert, globals: globals) estamos passando 2 parâmetros:

  • string string para avaliar -> "Request.Text == Response.Text"
  • Dados globals para o avaliador -> neste caso temos que fornecer um Request e um Response, a solicitação é a nossa resposta esperada e a resposta é a resposta recebida.

Como estamos preenchendo os dados no avaliador, agora podemos usar a string e avaliar, assim ela retornará true ou false.

Concluído

Terminamos, aqui você pode ver o TestMethod finalizado

[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;
}

Diagrama

Aqui está um diagrama de todo o fluxo que seguimos para chegar a este ponto, espero que se você não entendeu algo, isso esclareça tudo.

https://gyazo.com/1e3b7c9c2286844062878b4b8ca02d2d

E isso é tudo, isso é feito para casos únicos onde o caso é 1 para 1, o usuário envia um activity e o bot retorna outro único activity.

Espero que tenham gostado, o próximo serão os casos de fluxo de testes com mais de uma resposta.

https://gyazo.com/d964cfac395ed438a5282e60614863e7

Lembre-se de que todo o código está armazenado em meu github em este repositório.