Prueba de integración usando Bot Framework y DirectLine (3)

· 4 min de lectura

Esta es la última parte de la guía; en esta parte evaluaremos el texto de la afirmación en el json.

Ahora que usamos request y lo enviamos como activity al bot, obtuvimos el response y tenemos que comparar lo que assert en el json (la respuesta que hemos almacenado en el json, esta es la respuesta esperada) con la respuesta que obtuvimos del bot.

La siguiente explicación no cubrirá toda la información básica sobre cómo funciona Bot Framework. Si no lo comprende, consulte la documentación oficial.

Agregar Microsoft.CodeAnalysis a la solución

En primer lugar, debemos incluir CodeAnalysis como un paquete NuGet.

https://gyazo.com/ce97a60ecab998f162f6ac7a2ab2c9a7

Después de la instalación, recuerde agregar el paquete al archivo .cs.

using Microsoft.CodeAnalysis.CSharp.Scripting;

Creando un objeto Globals

Para evaluar, tenemos que pasar los parámetros al evaluador. Este evaluador necesita un archivo de configuración.

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

Esta parte es muy importante, en ese archivo de configuración incluiremos qué objetos compararemos, por lo que debemos pasarle la respuesta esperada y la respuesta recibida.

Con esa información estará usando el assert en el archivo json y estará evaluando lo que dice.

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

El EvaluateAsync<T> evalúa y devuelve T, en nuestro caso pasamos el string a evaluar y el globals, que tiene los datos donde evaluará.

Voy a intentar explicar esto con un ejemplo, usando una entrada (que tiene un nombre, solicitud, respuesta y afirmación).

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

Obtengamos las cosas importantes de esta entrada, primero la afirmación "assert": "Request.Text == Response.Text", esto significa que comparará el Request.Text con el Response.Text y devolverá el valor como booleano.

Pero cuando llamamos a la función await CSharpScript.EvaluateAsync<bool>(entry.Assert, globals: globals) estamos pasando 2 parámetros:

  • string cadena a evaluar -> "Request.Text == Response.Text"
  • globals datos para el evaluador -> en este caso tenemos que dar un Request y un Response, la solicitud es nuestra respuesta esperada y la respuesta es la respuesta recibida.

Mientras completamos los datos en el evaluador, ahora podemos usar la cadena y evaluar, por lo que devolverá true o false.

Hecho

Hemos terminado, aquí puedes ver el TestMethod terminado

[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

Aquí hay un diagrama de todo el flujo que seguimos para llegar a este punto; con suerte, si no entendiste algo, esto lo aclarará.

https://gyazo.com/1e3b7c9c2286844062878b4b8ca02d2d

Y eso es todo, esto se hace para casos únicos donde el caso es 1 a 1, el usuario envía un activity y el bot devuelve otro activity.

Espero que les haya gustado, el próximo serán los casos de flujo de prueba con más de una respuesta.

https://gyazo.com/d964cfac395ed438a5282e60614863e7

Recuerde que todo el código está almacenado en mi github en este repositorio.