Tutorial - Invores Quality Assurance Tester for VoiceXML

Introduction

IQAT can be run either from the command line or from the IqatPlan graphical interface.  The files in all the following examples are distributed in the installation directory \Program Files\Invores\Iqat\examples.  If you do not have a web server installed on your system, you can run the examples by using the file: URL scheme instead of http:.  For example, the URL of the example menu.v1.vxml in the default distribution directory would be file://c:/Program Files/Invores/Iqat/examples/menu.v1.vxml .

Manifest - /Program Files/Invores/Iqat/examples/

For this tutorial, the examples were copied from the distribution to a directory configured in the web server as /docs/iqtest.  Thus, the base URL used in most instances is http://localhost:8010/docs/iqtest .

A Simple Test Plan

Primary Testing

Consider the following VoiceXML application taken from http://www.w3c.org/Voice/Guide/.

<?xml version="1.0"?>
<vxml version="2.0">
<!-- version 1 -->
<menu id="choose">
<prompt>
Say one of: <enumerate/>
</prompt>
<choice next="start.vxml">
Sports
</choice>
<choice next="intro.vxml">
Weather
</choice>
<choice next="news.vxml">
News
</choice>
<noinput>Please say one of <enumerate/></noinput>
</menu>
</vxml>

This is a simple top-level menu selection which invokes the next phase of the application through one of three URL's.  Two things are important for the creation of a test plan:

  1. <menu> is a dialog-scope element;
  2. each <choice> element is implemented as a separate grammar.

There are three choices and thus three dialog-scope grammars.  A test plan Voice statement provides the expected response.  It specifies the utterance returned from the recognizer and the corresponding grammar which recognized the utterance.  This plan is menu1.txt.

menu1.txt
call:{}
// this statement triggers the second dialog scope grammar
voice:{utterance:"weather",grammar:"dialog-2"}

The above Voice statement provides the utterance "weather", and triggers the second dialog scope grammar.

When executed, an extract of the log output looks like:

execution log output

dlog03:menu ('choose')
prmp02:queueing TTS (Say one of:
    Sports
<break size="small"/>
    Weather
<break size="small"/>
    News
<break size="small"/>)
gram01:enable dialog grammar
gram01:enable dialog grammar
gram01:enable dialog grammar
voic01:timeout=7000ms completetimeout=-1ms incompletetimeout=-1ms maxspeechtimeout=-1ms nbest=1 confidencelevel=0.500 sensitivity=0.500 speedvsaccuracy=0.500
vxml09:choice next intro.vxml
vxml03:goto intro.vxml
docu02:fetch URI http://localhost:8010/docs/iqtest/intro.vxml

The test plan selected the second menu choice, and control was transferred to the document intro.vxml file. Since we are just interested in testing the logic of the VoiceXML application, the document intro.vxml is a stub, a VoiceXML document that does nothing.  With the three stub files for the three choices, we can extend the test plan to test all the choices and the <noinput> element.  Since <noinput> just causes the menu to be reiterated, there is no need to test it more than once, so we provide valid input for the second attempt.  The test plan follows.

menu1.v1.txt
// version 1
call:{}
voice:{grammar:"dialog-1",utterance:"sports"}
call:{}
voice:{grammar:"dialog-2",utterance:"weather"}
call:{}
voice:{grammar:"dialog-3",utterance:"news"}
call:{}
voice:{throw:"noinput"}
voice:{grammar:"dialog-3",utterance:"news"}

The empty Call statements mark the boundaries of a new call.  In addition, a Call statement can provide properties for the session object.  However, in this case, the Call statements are empty because the application is not sensitive to information on the session object.  If the application used properties from the session object, they would be set in the Call statement.  When this test plan is executed, the execution log for the final call, which includes the noinput event, looks like this:

dlog03:menu ('choose')
prmp02:queueing TTS (Say one of:
Sports
<break size="small"/>
Weather
<break size="small"/>
News
<break size="small"/>)
gram01:enable dialog grammar
gram01:enable dialog grammar
gram01:enable dialog grammar
voic01:timeout=7000ms completetimeout=-1ms incompletetimeout=-1ms maxspeechtimeout=-1ms nbest=1 confidencelevel=0.500 sensitivity=0.500 speedvsaccuracy=0.500
vxml07:event: noinput
vxml03:prompt element
prmp02:queueing TTS
vxml03:prompt element
prmp02:queueing TTS
dlog03:menu ('choose')
gram01:enable dialog grammar
gram01:enable dialog grammar
gram01:enable dialog grammar
voic01:timeout=7000ms completetimeout=-1ms incompletetimeout=-1ms maxspeechtimeout=-1ms nbest=1 confidencelevel=0.500 sensitivity=0.500 speedvsaccuracy=0.500
vxml09:choice next news.vxml
vxml03:goto news.vxml
docu02:fetch URI http://localhost:8010/docs/iqtest/news.vxml
dlog01:form $_internalName_31446 initialization
vxml02:block ($_internalName_31447)
call02:call returned no result
ivrt04:IVRT test plan completed

The stub file news.vxml is fetched, it executes an empty <block>, and the call ends.  This test plan is version 1 (menu.v1.txt), and when it is run, for the purposes of the tutorial, the output should be saved in a (version 1) log file, in this case menu.v1.log.  This log will be used when the application is modified and we need to do regression testing.

Regression Testing

Now the application is modified to add a fourth choice, and to avoid a noinput loop.  The modified (version 2) application looks like this.

<?xml version="1.0"?>
<vxml version="2.0">
<!-- version 2 -->
<menu id="choose">
  <prompt>
    Say one of: <enumerate/>
  </prompt>
  <choice next="start.vxml">
     Sports
  </choice>
  <choice next="intro.vxml">
     Weather
  </choice>
  <choice next="news.vxml">
     News
  </choice>
  <choice next="msgs.vxml">
     Messages
  </choice>
  <noinput>Please say one of <enumerate/></noinput>
  <noinput count="2">Please call back later<exit/></noinput>
</menu>
</vxml>

For regression testing, we want to verify that version 2 of the application did not break version 1 behavior.  We run the version 1 test plan against the version 2 application and compare the resulting log with the log for the same test plan against the version 1 application.  We keep track of the various log files in a matrix that matches the test plans against the versions of the application and lists the resulting log file.

                      \ Test Plan
Application  \
menu.v1.txt menu.v2.txt menu.v3.txt
menu.v1.vxml menu.v1.log

menu.v2.vxml menu.v2R.log menu.v2.log
menu.v3.vxml

menu.v3R.log
menu.v3.log

The regression comparison of the logs menu.v1.log and menu.v2R.log produces the following output.

16,17d
>      Messages
>   <break size="small"/>)
21d
> gram01:enable dialog grammar
40,41d
>      Messages
>   <break size="small"/>)
45d
> gram01:enable dialog grammar
64,65d
>      Messages
>   <break size="small"/>)
69d
> gram01:enable dialog grammar
88,89d
>      Messages
>   <break size="small"/>)
93d
> gram01:enable dialog grammar
105,106d
>      Messages
>   <break size="small"/>)
111d
> gram01:enable dialog grammar

The differences are expected.  There is one additional choice in version 2 of the application, so the prompt has an added option, and the new choice generates an additional enable for the new choice grammar.  These differences are repeated for each call in the test plan.  Note that the messages docu01 and docu02 have been selected for short compares.  These messages name the files being executed and thus will be different from one version of the log to the next.  A short compare compares only the presence of the message and not its contents. This eliminates irrelevant comparison differences and makes the regression log simpler to read.  Note also that the comparison skips the time stamp.  The regression test shows that the changes for version 2 of the application did not break the application's version 1 behavior.  Now the application can be tested with a version 2 test plan to exercise the new features of version 2 and to establish a base for version 3 regression, assuming that the application will continue to be modified.

The new test plan for version 2 adds calls to test the new choice and the additional noinput path.

Plan tab with voice statement selected
// version 2
call:{}
voice:{grammar:"dialog-1",   utterance:"sports"}
call:{}
voice:{grammar:"dialog-2",   utterance:"weather"}
call:{}
voice:{grammar:"dialog-3",utterance:"news"}
call:{}
voice:{grammar:"dialog-4",   utterance:"messages"}
call:{}
voice:{throw:"noinput"}
voice:{grammar:"dialog-3",utterance:"news"}
call:{}
voice:{throw:"noinput"}
voice:{throw:"noinput"}

When version 2 of the application is executed with version 2 of the test plan, the execution log shows that the new choice was selected appropriately and that two successive noinput events terminates a call.  Version 2 of the application has now been regression tested and tested with an updated test plan which targets the new version 2 features.

A Test Plan With Grammar Objects

The following VoiceXML document, fastfood.vxml, is a simple non-directed dialog in which the caller may provide several pieces of information in a single response.  The response is returned as an ECMAScript object from the recognizer.  Although the grammar is important to the application, it is not relevant to the test plan.  The plan simply specifies the object that should result from the recognition, which is what drives the logic of the application.  The ECMAScript function confirmPrompt(), is defined in the application's root document, which is omitted for simplicity.  It is included in the IQAT distribution examples directory.

At the <initial> element, named food, the dialog attempts to fill the slots entree, side, and drink. Each of these slots refers to a field with the corresponding name.  If the slot is filled, the field is bypassed.  Any slots that are not filled by the initial response are then individually prompted and filled. The application calls an ECMAScript function, confirmPrompt(), to build a confirmation prompt for the order, then calls a subdialog, place_order.cgi, to place the order, and get back an order number and the time to fulfillment.  The call then ends.

fastfood.vxml Page 2
    <block name="cfmprmpt">
      <var name="thisPrompt" expr="confirmPrompt(entree, side, drink)"/>
      <if cond="thisPrompt.length &gt; 0">
        <prompt><value expr="thisPrompt"/> Is this correct?</prompt>
      <else/>
        <assign name="confirm" expr="true"/>
        <assign name="order" expr="true"/>
      </if>
    </block>
    <field name="confirm" type="boolean">
      <help>Please answer yes or no.</help>
      <filled>
        <if cond="confirm == 'false'">
          <clear/>
        </if>
      </filled>
    </field>
    <subdialog src="place_order.cgi" name="order">
      <param name="entree" expr="entree"/>
      <param name="side" expr="side"/>
      <param name="drink" expr="drink"/>
      <filled>
        <prompt>
          Your order number is <value expr="order.ordnum"/>.
          It will be ready in <value expr="order.ordtim"/> minutes.
        </prompt>
      </filled>
    </subdialog>
    <block name="finish">
      <prompt>
        Thank you.  Good bye.
      </prompt>
      <disconnect/>
    </block>
  <catch event="nomatch">
    <prompt>
      I did not understand you.  Try again or say help.
    </prompt>
    <reprompt/>
  </catch>
  <catch event="nomatch" count="3">
    <prompt>
      I can not understand you.  Try again later.
    </prompt>
    <disconnect/>
  </catch>
  <catch event="noinput">
    <throw event="help"/>
  </catch>
  <catch event="noinput" count="2">
    <prompt>
      I did not hear any response.  Try again later. Good bye.
    </prompt>
    <disconnect/>
  </catch>
  <catch event="error subdialog">
    <if cond="reenter">
      <exit/>
    </if>
    <assign name="reenter" expr="true"/>
    <prompt>
      Sorry, your order cannot be filled.
      Code <value expr="_event"/>.
    </prompt>
    <exit/>
  </catch>
  </form>
  <catch event="connection.disconnect">
    <exit/>
  </catch>
</vxml>








fastfood.vxml Page 1
<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.0" application="fastfood.app.vxml">
  <var name="reenter" expr="false"/>
  <form id="root">
    <property name="confidencelevel" value=".8"/>
    <property name="inputmodes" value="voice"/>
    <var name="sctr" expr="0"/>
    <var name="ectr" expr="0"/>
    <var name="dctr" expr="0"/>
    <block name="welcome">Welcome to Burger Hut.</block>
    <grammar type="application/srgs+xml" src="FF2.grxml" version="1.0"/>
    <initial name="food">
      <prompt>What would you like to order?</prompt>
      <help>
        Menu choices are hamburgers, cheeseburgers, pizzas, drinks,
        fries and onion rings.
        <reprompt/>
      </help>
    </initial>
    <field name="entree">
      <grammar type="application/srgs+xml" src="FFe.grxml"/>
      <prompt>Would you like an entree?</prompt>
      <filled>
        <if cond="entree == 'yes' &amp;&amp; ectr &lt; 3">
          <assign name="ectr" expr="ectr + 1"/>
          <assign name="entree" expr="undefined"/>
          <prompt>
            Entrees are hamburgers, cheeseburgers, and pizzas.
            What would you like?
          </prompt>
        <elseif cond="entree == 'no'"/>
          <assign name="entree" expr="''"/>
        </if>
      </filled>
      <help>
        Entrees are hamburgers, cheeseburgers, and pizzas.
        <reprompt/>
      </help>
    </field>
    <field name="side" cond="entree == 'hamburger' || entree == 'cheeseburger'">
      <grammar type="application/srgs+xml" src="FFs.grxml"/>
      <prompt>Would you like a side order?</prompt>
      <help>
        Side orders are french fries or onion rings.
        <reprompt/>
      </help>
      <filled>
        <if cond="side == 'yes' &amp;&amp; sctr &lt; 3">
          <assign name="sctr" expr="sctr + 1"/>
          <assign name="side" expr="undefined"/>
          <prompt>
            Side orders are french fries or onion rings.
          </prompt>
        <elseif cond="side == 'no'"/>
          <assign name="side" expr="''"/>
        </if>
      </filled>
    </field>
    <field name="drink">
      <grammar type="application/srgs+xml" src="FFd.grxml"/>
      <prompt>Would you like a drink?</prompt>
      <help>
        Drinks are coke, seven up, sprite, coffee, tea, or iced tea.
        <reprompt/>
      </help>
      <filled>
        <if cond="drink == 'yes' &amp;&amp; dctr &lt; 3">
          <assign name="dctr" expr="dctr + 1"/>
          <assign name="drink" expr="undefined"/>
          <prompt>
            Drinks are coke, seven up, sprite, coffee, tea, or iced tea.
          </prompt>
        <elseif cond="drink == 'no'"/>
          <assign name="drink" expr="''"/>
        </if>
      </filled>
    </field>

When the dialog attempts to fill the slots entree, side, and drink, the recognizer can return an object which may have any of these properties set.  The test plan begins by returning the slots entree and drink, which we assume the grammar extracted from the specified utterance.  The slots are top level properties in the interpretation property of the first Voice statement in the plan.  This is what the recognizer is expected to respond when it hears the corresponding utterance.  In IQAT, the interpretation property of a Voice statement is displayed with a background green tint.  This is a reminder that the content of the field is JavaScript object literal notation, and as such must be syntactically correct.

call:{}
// fastfood.vxml IQAT test plan
// prompt what would you like to order?
voice:{utterance:"I'd like a hamburger and a coke", confidence:0.80, grammar:"dialog-1", interpretation:{drink:"coke", entree:"hamburger"}}
// the side slot is missing, so we should prompt for that slot
// prompt would you like a side order?
voice:{utterance:"no", confidence:0.90}
// prompt you ordered ... is this correct?
voice:{utterance:"yes", confidence:0.90}
//prompt your order number is ... it will be ready in ... minutes.

The response satisfies the <initial> element and fills the fields with the corresponding slot names.  The form interpretation algorithm will then select the field side as the next field to be filled.  The prompt expected is indicated in the plan comment, and the plan response is another voice statement with the utterance "no".  This fills the field side and selects in order the <block> cfmprmpt, the <field> confirm, the <subdialog> order, and the <block> finish.  When this plan is run using the IqatPlan Verify Tab, the following log is produced.  Some detail has been suppressed in the interest of space.  The output has been annotated in the right-hand column to explain the log output.

 Execution Notes


 the name of the input test plan

 the URL of the VoiceXML document being tested


 load the VoiceXML document
 load the root document
 the root document's ECMAScript definitions
 fastfood.vxml document scope variables

 initialze form ID root
 dialog scope variables


 welcome block


 initial element


 default properties for the initial voice request


 filled element for the filled field entree

 filled element for the filled field drink

 field side was not filled, so it is now selected by the FIA


 filled element for field side


 block cfmprmpt calls an ECMAScript function to get a confirm prompt



 the confirm prompt

 field confirm solicits a response to the confirm prompt

 filled element for field confiorm
 subdialog order places the order with host logic

 the document response to the subdialog request
 the dialog scope variables


 an unnamed block


 the subdialog document returns
 the filled element for subdialog order


 execute the block finish

 the goodbye prompt from block finish
 the block executes a disconnect
 the disconnect event is thrown
 the catch element handling the disconnect event is executed
 the application ends
 the test plan is complete
fastfood.vxml Execution Log with fastfood.plan1.txt
iqat00:Invores Quality Assurance Tester for VoiceXML (copyright (c) 2009 Invores Systems)
iqat01:IQAT (1.0) executing test plan C:\invores\docs\iqtest\fastfood.plan1.txt
docu02:initial VoiceXML document 'http://localhost:8010/docs/iqtest/fastfood.vxml'
...
docu02:fetch URI http://localhost:8010/docs/iqtest/fastfood.vxml
docu02:fetch URI http://localhost:8010/docs/iqtest/fastfood.app.vxml
vxml03:script inline
vxml01:var (reenter=false)
...
dlog01:form root initialization
vxml01:var (sctr=0)
vxml01:var (ectr=0)
vxml01:var (dctr=0)
vxml02:block (welcome)
vxml03:prompt element
prmp02:queueing TTS (Welcome to Burger Hut.)
vxml02:initial (food)
prmp02:queueing TTS (What would you like to order?)
gram01:enable dialog grammar
voic01:timeout=7000ms completetimeout=-1ms incompletetimeout=-1ms maxspeechtimeout=-1ms nbest=1 confidencelevel=0.800 sensitivity=0.500 speedvsaccuracy=0.500
vxml03:if (entree == 'yes' && ectr < 3)
vxml03:elseif (entree == 'no')
vxml03:if (drink == 'yes' && dctr < 3)
vxml03:elseif (drink == 'no')
vxml02:field (side)
prmp02:queueing TTS (Would you like a side order?)
...
vxml03:if (side == 'yes' && sctr < 3)
vxml03:elseif (side == 'no')
vxml03:assign (side = '')
vxml02:block (cfmprmpt)
vxml01:var (thisPrompt=confirmPrompt(entree, side, drink))
vxml03:if (thisPrompt.length > 0)
vxml03:prompt element
prmp02:queueing TTS (You ordered a hamburger  and coke.  Is this correct?)
vxml02:field (confirm)
...
vxml03:if (confirm == 'false')
vxml02:subdialog (order)
docu02:fetch URI http://localhost:8010/docs/iqtest/place_order.cgi
dlog01:form order_time initialization
vxml01:var (entree)
vxml01:var (side)
vxml01:var (drink)
vxml02:block ($_internalName_31423)
vxml01:var (ordnum=17)
vxml01:var (ordtim=10)
vxml03:return element
vxml03:prompt element
prmp02:queueing TTS (Your order number is  17 .
          It will be ready in  10  minutes.)
vxml02:block (finish)
vxml03:prompt element
prmp02:queueing TTS (Thank you.  Good bye.)
vxml03:disconnect element
vxml07:event: connection.disconnect.hangup
vxml03:exit element
call02:call returned no result
iqat04:IQAT test plan completed

With any combination of three slots returned, it will take eight calls to test the go-right logic for the application.The help elements should be added to the test plan, which will increase number of calls  A full test plan for the application is included in the IQAT distribution.

Multiple Results

The following application uses multiple results from the recognizer to increase the possibility of getting a correct recognition on the first try.  Of course, with multiple results, some additional information must be taken into account in order for the application to try to correctly select among the recognizer's responses.  In this application, the request is for an account number, and the number has a check digit.  The first result which matches the check digit is selected.  A recognizer always presents multiple results ordered from highest to lowest confidence, and so the test plan is designed to return them in the same way.  The application's VoiceXML follows, along with annotations in the right-hand column.  The check digit verification is in the application's root document.

 Application notes




 set the maxnbest property greater than 1


 the grammar specifies numeric recognition with multiple results

 try voice recognition first



 the selectResult() function is defined in the root document; it loops through the passed lastresult$ array looking for a result that passes the check digit test



 a good result was found, so set the next field to be bypassed

 first time no match



 second time nomatch

 fill this form item variable to trigger the next field


 execute only if acctv was set to 0
 DTMF input


 verify that the check digit is correct



 DTMF first time nomatch



 DTMF second time nomatch


 disconnect after two no-matches


 block executed if a correct account number has been entered


 the next VoiceXML document in the application

 dialog scope first time noinput



 dialog scope second time noinput





 error handler
 avoid recursion









 disconnect handler



 multiple.vxml
<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.0" application="multiple.app.vxml">
  <var name="reenter" expr="false"/>
  <form id="root">
    <property name="maxnbest" value="5"/>
    <property name="confidencelevel" value=".5"/>
    <var name="account" expr="null"/>
    <grammar type="application/srgs+xml" src="mr1.grxml" version="1.0"/>
    <field name="acctv">
      <property name="inputmodes" value="voice"/>
      <prompt>Please say your account number.</prompt>
      <filled>
        <assign name="account" expr="selectResult(application.lastresult$)"/>
        <if cond="!account.found">
          <assign name="acctv" expr="undefined"/>
          <throw event="nomatch"/>
        </if>
        <assign name="acctd" expr="0"/>
      </filled>
      <nomatch>
        I did not understand what you said.
        Please say your account number once more.
      </nomatch>
      <nomatch count="2">
        Let's try your phone's keypad.
        <assign name="acctv" expr="0"/>
      </nomatch>
    </field>
    <field name="acctd" type="digits?length=5" cond="acctv == 0">
      <property name="inputmodes" value="dtmf"/>
      <prompt>Please enter your account number.</prompt>
      <filled>
        <if cond="!verifyCheck(acctd)">
          <throw event="nomatch"/>
        </if>
      </filled>
      <nomatch>
        I did not understand what you said.
        Please enter your account number once more.
      </nomatch>
      <nomatch count="2">
        I am unable to get your account number.  PLease call back later.
        <disconnect/>
      </nomatch>
    </field>
    <block name="finish">
      <assign name="customer.account" expr="(acctv != 0) ? acctv : acctd"/>
      <goto next="lookup.vxml"/>
    </block>
  <catch event="noinput">
    <prompt>I did not hear any response.</prompt>
    <reprompt/>
  </catch>
  <catch event="noinput" count="2">
    <prompt>
      I did not hear any response.  Try again later. Good bye.
    </prompt>
    <disconnect/>
  </catch>
  <catch event="error">
    <if cond="reenter">
      <exit/>
    </if>
    <assign name="reenter" expr="true"/>
    <prompt>
      Sorry, error <value expr="_event"/> has occurred. Good bye.
    </prompt>
    <exit/>
  </catch>
  </form>
  <catch event="connection.disconnect">
    <exit/>
  </catch>
</vxml>

The first call in the following test plan returns two results for the first attempt, both of which will fail the check digit test.  On the second attempt at voice input, the plan returns three results, and the third result will pass the check digit test, which is a simple mod 10 test.  The second call fails both attempts, and the application falls back on DTMF entry.  The plan then provides a DTMF sequence which has a correct check digit.

Test Plan notes

first input response
result1 sets application.lastresult$[0].interpretation to '21349'
note that the results should be ordered by confidence
result2 sets application.lastresult$[1].interpretation to '21345'

second attempt at input provides three results




this result satisfies the check digit test

the second test call
both results fail the check digit test




a second attempt at voice input also fails the check digit test




the application requests DTMF input; the plan provide correct input
// multiple.plan.txt
call:{}
voice:{
  result1{confidence:0.85,inputmode:'voice',interpretation:'21349',
    utterance:'two one three four nine'},
  result2:{confidence:0.80,inputmode:'voice',interpretation:'21345',
    utterance:'two one three four five'}}
voice:{
  result1:{confidence:0.85,inputmode:'voice',interpretation:'21349',
    utterance:'two one three four nine'},
  result2:{confidence:0.80,inputmode:'voice',interpretation:'21345',
    utterance:'two one three four five'},
  result3:{confidence:0.70,inputmode:'voice',interpretation:'26345',
    utterance:'two six three four five'}}
call:{}
voice:{
  result1:{confidence:0.85,inputmode:'voice',interpretation:'21349',
    utterance:'two zero three four nine'},
  result2:{confidence:0.80,inputmode:'voice',interpretation:'21345',
    utterance:'two zero three four five'}}
voice:{
  result1:{confidence:0.85,inputmode:'voice',interpretation:'21349',
    utterance:'two zero three four nine'},
  result2:{confidence:0.80,inputmode:'voice',interpretation:'21345',
    utterance:'two zero three four five'}}
dtmf:{utterance:"26345"}

Recording

When an application needs to make a recording, the test plan provides several different options. If the content of the recording is irrelevant, a specification of the recording duration is all that is needed in the Record test plan statement.  IQAT will generate sound for the requested length, at 8000 samples per second, and return it as the value of the recording. If the type attribute is audio/x-wav, a .wav header will be added to the generated sound.  Any other type will be treated as audio/basic for the purposes of the test.  If the content of the recording is important, IQAT can read a previously recorded file and return its content to the <record> element.  This is specified with the file property of the Record test plan statement.

Test Plan
//record test - make a recording, then confirm with a 1
call:{}




// a minmal Record test plan statement specifies the generation
// of 10 seconds of sound to provide input for the <record> element
record:{duration:10}





















// a DTMF test plan statement provides the 1 which the application
// requests for confirmation after playing the recording
dtmf:{utterance:"1"}
















































rec1.vxml
<?xml version="1.0"?>
<vxml application="rec1_app.vxml" version="2.0">
  <form id="frmRecord">
    <var name="reenter" expr="false"/>
    <var name="errmsg" expr="''"/>
    <var name="atts" expr="0"/>
    <var name="sessid" expr="callid"/>
    <var name="logpfx" expr="appname + '.' + appid + '.frmRecord'"/>
    <record name="recording" type="audio/x-wav"
            finalsilence="3s" maxtime="100s"
            dtmfterm="true" beep="true">
      <prompt count="1">
        <audio expr="'recPrompt1.wav'">
          Please record your message after the tone,
        </audio>
      </prompt>
      <prompt count="2">
        <audio expr="'recPrompt2.wav'">
          Please record your message after the tone,
        </audio>
      </prompt>
      <filled>
        <assign name="lastrec" expr="recording"/>
        <if cond="confirm == false">
          <goto expr="recordNextSucceed"/>
        </if>
      </filled>
      <catch event="nomatch noinput" count="2">
        <assign name="errmsg" expr="'noinput/nomatch limit'"/>
        <throw event="apperr.record.fail"/>
      </catch>
    </record>
    <field name="conf" cond="confirm">
      <dtmf>1 | 2</dtmf>
      <prompt>
        <audio expr="'IHeard.wav'">
          I heard
        </audio>
        <value expr="recording"/>
        <audio expr="'IfCorrect.wav'">
          If this is correct, press 1. To try again, press 2.
        </audio>
      </prompt>
      <filled>
        <if cond="conf != '1'">
          <assign name="atts" expr="atts + 1"/>
          <if cond="atts >= maxatts">
            <assign name="errmsg" expr="'noinput/nomatch limit'"/>
            <throw event="apperr.record.fail"/>
          <else/>
            <clear namelist="recording conf"/>
            <reprompt/>
          </if>
        <else/>
          <goto next="start.vxml"/>
        </if>
      </filled>
      <catch event="error">
        <assign name="errmsg" expr="'confirm'"/>
        <throw event="apperr.record.fail"/>
      </catch>
    </field>
    <catch event="apperr.record">
      <var name="msg" expr="''"/>
      <if cond="typeof _message != 'undefined'">
        <assign name="msg" expr="' message:' + _message"/>
      </if>
      <log><value expr="logpfx"/> call:<value expr="sessid"/> <value expr="errmsg"/> event:<value expr="_event"/><value expr="msg"/></log>
      <exit/>
    </catch>
    <catch event="error">
      <if cond="reenter">
        <log>error recursion <value expr="_event"/></log><exit/>
      </if>
      <assign name="reenter" expr="true"/>
      <assign name="errmsg" expr="'unexpected'"/>
      <throw event="apperr.record.fail"/>
    </catch>
  </form>
</vxml>

Transfer

The Transfer test plan statement provides response for a <transfer> element.  The example document xfr1.vxml shows a simple blind transfer.  Note that although the VoiceXML specification says that a blind transfer always throws a connection.disconnect.transfer event, the Transfer statement does not make that assumption.  The example xfr1.txt test plan shows the transfer statement with the explicit disconnect outcome. This is done because <transfer> is often extended by a VoiceXML platform, and IQAT tries to support as many platform variations as possible.

Object

Since the <object> element is by definition, platform dependent, IQAT performs only minimal processing with it.  In order to verify the object when it is selected by the Form Interpretation Algorithm, the Object test plan statement has a required property, classid.  This should match the value of the classid attribute of the <object> element.  The other property of the Object statement is result.  This is an ECMAScript object with an arbitrary set of properties.  This becomes the value of the <object> element's form item variable.  The following test plan is used to test the document obj1.vxml.

obj1.txt
// test plan for the document obj1.vxml
call:{}
// object element example
// verify the object's classid, return an object with a status property
object:{classid:"com.invores.vxml.outdial",result:{status:'busy'}}
// this iteration return a connect status
object:{classid:"com.invores.vxml.outdial",result:{status:'connect'}}

Comments

A test plan can be annotated with comments using Javascript // or /* ... */ comment conventions.  IQATPlan is line-oriented and restricts comments to their own lines.  Single line comments are preceded by // and multi-line comments are bounded by /* ... */ .  A checkbox in the Comment tab determines the type of the comment.  A test plan created outside of IQATPlan, for example with a text editor, can have comments on the same line as plan statements.  However, if such a plan is loaded into IQATPlan, the same-line comments will be omitted, and will not be saved if the plan is updated within IQATPlan.