You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After spending a week creating middleware, and doing it with TDD, the thing I settled on above all is the need for a TestBotContext. When calling any of the middleware functions (events), what's really happening is the state of the context is being modified in many (most?) cases.
For example, in the case of human handoff, where messages need to be sent back on the context passed in, and not via the bot, all that's really happening is the responses array is having another Activity pushed on it. Something like this (with logic assumed):
onReceive(context: Partial<BotContext>,next: ()=>Promise<void>){if(userWantsAgent)context.reply("Connecting you to an agent.");// modifies context.responses}
It's much simpler to test if I can pass a context in, and then inspect it afterwards, to ensure there's a particular reply waiting in the wings. As best I can tell, there isn't an easy way to just create an empty context, so I wound up implementing one on my own. The moment I did that, my tests became easier to write and more elegant. My implementation isn't complete, but it was what I needed for my tests.
classTestContextimplementsBotContext{constructor(conversationReference: ConversationReference,request: Activity|string){if(typeofrequest!=="object"){request={type: "message",text: request};}this.conversationReference=conversationReference;this.request=request;this.bot=newBot(newTestAdapter);this.bot.createContext=(reference: ConversationReference,onReady: (context: BotContext)=>void)=>{onReady(this);returnnewPromise(()=>{});};this.responses=[];}publicrequest: Activity;publicresponses: Activity[];publicbot: Bot;publicresponded: boolean=false;publicconversationReference: ConversationReference;publicstate: BotState;publictemplateManager: TemplateManager;publicdelay(duration: number){returnthis;}publicdispose(){}publicendOfConversation(code?: string){returnthis;}publicreplyWith(id: string,data: any){returnthis;}publicflushResponses(){returnnewPromise<ConversationResourceResponse[]>((value)=>{});}publicshowTyping(){returnthis;}publicreply(textOrActivity : string|Activity){if(typeoftextOrActivity!=="object"){textOrActivity={type: "message",text: textOrActivity};}this.responses.unshift(textOrActivity);returnthis;}}// sample test:it("Agent can list queue",(done)=>{constcontext=newTestContext(agentReference,"#list");constprovider=getProvider(HandoffUserState.queued);newHandoffMiddleware(provider).receiveActivity(context,next);assert(provider.getQueue.called,"getQueue not called");assert(next.notCalled,"next called");// (a sinon spy)assert(context.responses.length===1,"Wrong number of responses");assert(context.responses[0].text.indexOf(userReference.user.name)>-1,"Name not listed")done();});
The text was updated successfully, but these errors were encountered:
So one of the changes I'm planning to make is to turn the context into an actual class so you'll be able to just create it very short. I think it's definitely a good suggestion to be able to test middleware in isolation so I'll ensure that's possible. In fact I'll try to shift to testing our internal middleware using the same technique.
You can now very easily spin up a new TurnContext that you can pass directly to your middleware. Closing and please comment if the current code doesn't satisfy this need.
After spending a week creating middleware, and doing it with TDD, the thing I settled on above all is the need for a TestBotContext. When calling any of the middleware functions (events), what's really happening is the state of the context is being modified in many (most?) cases.
For example, in the case of human handoff, where messages need to be sent back on the context passed in, and not via the bot, all that's really happening is the responses array is having another
Activity
pushed on it. Something like this (with logic assumed):It's much simpler to test if I can pass a context in, and then inspect it afterwards, to ensure there's a particular reply waiting in the wings. As best I can tell, there isn't an easy way to just create an empty context, so I wound up implementing one on my own. The moment I did that, my tests became easier to write and more elegant. My implementation isn't complete, but it was what I needed for my tests.
The text was updated successfully, but these errors were encountered: