Teste de integração usando Bot Framework e DirectLine (3)
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.
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:
stringstring para avaliar ->"Request.Text == Response.Text"- Dados
globalspara o avaliador -> neste caso temos que fornecer umRequeste umResponse, 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.
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.
Lembre-se de que todo o código está armazenado em meu github em este repositório.


