Reputation: 364
We've trying to unit test every case that we have stored in a certain Dictionary, it seems to be working fine when the user sends and string and the test has to answer with a string. But we can't find any documentation on how to test the other kind of dialogs, like with attachments, buttons, etc.
We wish to make a dictionary of string,objects where the string is what we ask the bot and de object is either a string, Attachment, Dialog.
This is how we store the answers:
public static Dictionary<string, object> data = new Dictionary<string, object>{
{"Nuevo", "Que quieres crear?"},
{"Ayuda", "Ya te ayudas!"},
{"Adios", "Nos vemos!"},
{
"Coche",
new Attachment() {
ContentUrl = "https://media.ed.edmunds-media.com/subaru/impreza/2006/oem/2006_subaru_impreza_sedan_sti_fq_oem_1_500.jpg",
ContentType = "image/png",
Name = "Subaru_Impreza.png"
}
},
{
"Moto",
new Attachment() {
ContentUrl = "http://motos.honda.com.co/sites/default/files/motos/cb-1000-r-cc-menu-honda.png",
ContentType = "image/png",
Name = "moto.png"
}
},
{
"Perro",
new Attachment() {
ContentUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Taka_Shiba.jpg/1200px-Taka_Shiba.jpg",
ContentType = "image/png",
Name = "ShibaInu.png"
}
}
};
This is how the bot works and returns everything, this is working as intended for at least text and attachments but we haven't done it for more type of messages.
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
var r = context.MakeMessage();
foreach (var item in data)
{
if (item.Key == activity.Text)
{
if (item.Value is Attachment)
{
r.Attachments = new List<Attachment>() { item.Value as Attachment };
}
if (item.Value is string)
{
r.Text = item.Value.ToString();
}
break;
}
}
// return our reply to the user
await context.PostAsync(r);
context.Wait(MessageReceivedAsync);
}
But when we want to make the test for it, it only works when what we send is a string not a IMessageActivity, which works in the emulator.
The code for the test:
[TestMethod]
public async Task Pregunta_respuesta_prueba()
{
foreach (var item in RootDialog.data)
{
var preg = item.Key;
var resp = item.Value;
if (item.Value is Attachment)
{
Attachment auxText = resp as Attachment;
resp = auxText.ContentUrl;
}
using (ShimsContext.Create())
{
// Arrange
var waitCalled = false;
object message = null;
var target = new RootDialog();
var activity = new Activity(ActivityTypes.Message)
{
Text = preg
};
var awaiter = new Microsoft.Bot.Builder.Internals.Fibers.Fakes.StubIAwaiter<IMessageActivity>()
{
IsCompletedGet = () => true,
GetResult = () => activity
};
var awaitable = new Microsoft.Bot.Builder.Dialogs.Fakes.StubIAwaitable<IMessageActivity>()
{
GetAwaiter = () => awaiter
};
var context = new Microsoft.Bot.Builder.Dialogs.Fakes.StubIDialogContext();
Microsoft.Bot.Builder.Dialogs.Fakes.ShimExtensions.PostAsyncIBotToUserStringStringCancellationToken = (user, s1, s2, token) =>
{
message = s1;
Console.WriteLine(message);
return Task.CompletedTask;
};
Microsoft.Bot.Builder.Dialogs.Fakes.ShimExtensions.WaitIDialogStackResumeAfterOfIMessageActivity = (stack, callback) =>
{
if (waitCalled) return;
waitCalled = true;
// The callback is what is being tested.
callback(context, awaitable);
};
// Act
await target.StartAsync(context);
// Assert
Assert.AreEqual(resp, message);
}
}
}
If you check this part of the code
Microsoft.Bot.Builder.Dialogs.Fakes.ShimExtensions.PostAsyncIBotToUserStringStringCancellationToken = (user, s1, s2, token) =>
{
message = s1;
Console.WriteLine(message);
return Task.CompletedTask;
};
```
It does only works when the bot is returning an string, we can't even check if it is an activiy, this happens because the Fake Context that we create for the test is not working as expected.
That IDialogContext that we are faking doesnt seem to work at all when it is an object, but it does work when it is a string.
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
/// Here when the test is running, this context.MakeMessage is null, but when the bot
/// is working, it wors perfectly.
var r = context.MakeMessage();
foreach (var item in data)
{
if (item.Key == activity.Text)
{
if (item.Value is Attachment)
{
r.Attachments = new List<Attachment>() { item.Value as Attachment };
}
if (item.Value is string)
{
r.Text = item.Value.ToString();
}
break;
}
}
// return our reply to the user
await context.PostAsync(r);
context.Wait(MessageReceivedAsync);
}
To try this out you can try to test with an attachment, code is in this repository.
Upvotes: 3
Views: 470
Reputation: 8292
In stead of using PostAsyncIBotToUserStringStringCancellationToken, you can use context.PostAsyncIMessageActivityCancellationToken And, in the RootDialog's MessageReceivedWithTextAsync respond with an activity reply instead of just a string.
public async Task MessageReceivedWithTextAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
string r = "";
foreach (var item in dataText)
{
if (item.Key == activity.Text)
{
r = item.Value;
break;
}
}
var reply = activity.CreateReply(r);
foreach (var item in dataAtt)
{
if (item.Key == activity.Text)
{
reply.Attachments.Add(item.Value);
reply.Text = "attachment";
break;
}
}
if ((string.IsNullOrWhiteSpace(r) || r == null) && reply.Attachments.Count == 0)
{
reply.Text = "No tengo respuesta para eso.";
}
// return our reply to the user
await context.PostAsync(reply);
}
Here are the changes to the test method:
[TestMethod]
public async Task Bot_Test_Attachments()
{
foreach (var item in RootDialog.dataAtt)
{
var preg = item.Key;
var att = item.Value;
using (ShimsContext.Create())
{
var waitCalled = false;
IMessageActivity message = null;
var target = new RootDialog();
var activity = new Activity(ActivityTypes.Message)
{
Text = preg,
From = new ChannelAccount("id","name"),
Recipient = new ChannelAccount("recipid","recipname"),
Conversation = new ConversationAccount(false,"id","name")
};
var awaiter = new Microsoft.Bot.Builder.Internals.Fibers.Fakes.StubIAwaiter<IMessageActivity>()
{
IsCompletedGet = () => true,
GetResult = () => activity
};
var awaitable = new Microsoft.Bot.Builder.Dialogs.Fakes.StubIAwaitable<IMessageActivity>()
{
GetAwaiter = () => awaiter
};
var context = new Microsoft.Bot.Builder.Dialogs.Fakes.StubIDialogContext();
context.PostAsyncIMessageActivityCancellationToken = (messageActivity, token) => {
message = messageActivity;
return Task.CompletedTask;
};
Microsoft.Bot.Builder.Dialogs.Fakes.ShimExtensions.WaitIDialogStackResumeAfterOfIMessageActivity = (stack, callback) =>
{
if (waitCalled) return;
waitCalled = true;
callback(context, awaitable);
};
await target.MessageReceivedWithTextAsync(context, awaitable);
Assert.AreEqual(att, message.Attachments[0]);
}
}
}
Upvotes: 1