Prueba de integración usando Bot Framework y DirectLine (3)
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.
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:
stringcadena a evaluar ->"Request.Text == Response.Text"globalsdatos para el evaluador -> en este caso tenemos que dar unRequesty unResponse, 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á.
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.
Recuerde que todo el código está almacenado en mi github en este repositorio.


