As A General Guideline For Quality Center: Working With Workflow
As A General Guideline For Quality Center: Working With Workflow
1. Error Handling
The both code fragments will work the same way when no problems arise during the
code execution. But what happens if, for example, the user has no permissions to
modify BG_PRIORITY field? The left fragment will not update the field and will cause
the browser crash. The second will not update the field, but it will show the correct
error to the user and the browser will not crash.
Combine all values that require the same code to be executed to the
same Case statement
VBScript allows you to put several values into one Case statement. Example:
In the following example the same code [Code A] should be executed when
the {Variable} value is X or Y. Instead of creating 2 cases (code on the left
side), you can put X and Y into 1 case (code on the right side).
See: Code Templates -> Working With TestDirector API -> Getting the current
connection (current session)
See: Code Templates -> Working With TestDirector API -> Keeping Last Used
Value In Fields
Use mailing methods available in OTA to send the custom mails to the
users.
OTA allows access to TestDirector mailing, which allows you to:
- Create custom conditions that cannot be implemented using the
automatic notification system of TestDirector.
- Change the Subject or the text of the e-mail.
- Send an e-mail to the specific TestDirector groups or TestDirector
users.
- Send the e-mail from the specific user, rather then “admin” as
automatic mail notification does.
The mailing methods are available from any TestDirector object (like Defect,
Test, etc.) or directly from the TDConnection object. Using the Mail method
from the TestDirector object you can send the e-mail that contains that object
and your custom subject/text. Using the Mail method from the TDConnection
object allows you to send any custom mail.
See: Code Templates -> Working With TestDirector API -> Sending an E-Mail
from the Workflow
4. Workflow Objects
See: Code Templates -> Working With the Fields -> Setting Field Properties
Reset the layout for all fields before setting the fields’ layout (PageNo
and ViewOrder).
Since the fields have some default predefined order, it is important to reset
this order before defining the new, custom one.
Consider the following example:
Bug_Fields(“BG_SEVERITY”).ViewOrder = 1
Bug_Fields(“BG_PRIORITY”).ViewOrder = 2
For i=0 To Bug_Fields.Count
Bug_Fields.FieldById(i).ViewOrder = 100
Next
Bug_Fields(“BG_SEVERITY”).ViewOrder = 1
Bug_Fields(“BG_ PRIORITY”).ViewOrder = 2
In the first example, the ViewOrder is set only for BG_SEVERITY and
BG_PRIORITY fields. The ViewOrder of other fields is unknown (what if
ViewOrder of some other field is 1 as well? In this case, BG_ PRIORITY will be
third and not the second field on the form), so you do not actually know how
the fields will appear on the form. In the second example, the ViewOrder of
all the fields is reset to some big value, which ensures that BG_SEVERITY and
BG_PRIORITY fields will be indeed the first on the form.
See: Code Templates -> Working With the Fields -> Resetting Properties of All
Fields
II. Code Templates
1. Error Handling
1.1 Show the Standard Error to the User
Purpose: The following procedure shows the standard error to the user.
Code Location: The code should be added once to each Workflow script (Defects,
Test Plan, etc.).
Templates Used: None
Arguments:
strFunctionName - The name of the function or procedure in which the error have
happened
Return Value: None
Code Template:
Sub PrintError(strFunctionName)
If Err.Number <> 0 Then
MsgBox “Error #” & Err.Number & “: “ & Err.Description, _
vbOKOnly+vbCritical, _
“Workflow Error in Function “ & strFunctionName
End If
End Sub
Template 1.1
Code Template:
Function|Sub {Function|Sub_Name}()
On Error Resume Next
[Your code here]
PrintError “{Function|Sub_Name}”
On Error GoTo 0
End Function|Sub
Template 1.2
Code Template:
Sub {Object}_SetFieldProp(strFieldName,
blnIsVisible, blnIsReadOnly, blnIsRequired,
intPageNo, intViewOrder)
On Error Resume Next
With {Object}_Fields(strFieldName)
.IsVisible = blnIsVisible
.IsReadOnly = blnIsReadOnly
.IsRequired = blnIsRequired
.PageNo = intPageNo
.ViewOrder = intViewOrder
End With
PrintError “{Object}_SetFieldProp”
On Error GoTo 0
End Sub
Template 2.1.1
Usage Example: For example, if you have created the procedure Sub
Bug_SetFieldProp using this template, you can use it anywhere in the script like:
Code Template:
Sub {Object}_SetFieldFlags(strFieldName,
blnIsVisible, blnIsReadOnly, blnIsRequired)
On Error Resume Next
With {Object}_Fields(strFieldName)
.IsVisible = blnIsVisible
.IsReadOnly = blnIsReadOnly
.IsRequired = blnIsRequired
End With
PrintError “{Object}_ SetFieldFlags”
On Error GoTo 0
End Sub
Template 2.1.2
Usage Example: See the examples for templates 2.1.1 and 2.2.
Usage Example: in the following example, the IsVisible property of all defect fields
is reset:
Code Template:
Code Template:
Usage Example: for example you want to organize the fields on the Add Defect
form, so that all relevant system fields would be on first page, and all other fields
would be on the second page, the AddDefect_SetPageFieldsOrder procedure created
by template can be used in the following way:
Usage Example: For example if you’ve created the procedure Sub Bug_SetList
using this template, and you want to set the list for BG_CLOSING_VERSION,
BG_DETECTION_VERSION, BG_PLANNED_CLOSING_VER fields according to the
value of the BG_PROJECT field, you can use the following code anywhere in the
script:
2.5 Ensuring That User Updates Some Field When Another Field Is Changed
Purpose: The code below allows to ensure that some field (“dependant field”) is
updated when another field (“master field”) is changed to some value. For example:
when the Status (aka “master field”) field is changed to “Fixed”, we want to ensure
that the user updates R&D Comments (aka “dependant field”).
Code Location: It should be added to the code of each workflow script (Defects,
Test Plan, etc.), separately for each object. The {Mode} should be replaced with the
name of the mode (TestPLan, TestLab, etc.); the {Object} should be replaced with
object name (Bug, Test, etc.). {MasterField} should be replaced with the name of
the “master field” (or with field label for flag names); {DependantField} should be
replaced with the name of the “dependant field” (or with field label for flag names).
See the example below for correct template usage.
Templates Used: None
Arguments: None
Return Value: None
Note: Since the template is only a part of the code, and doesn’t represent a
separate function or procedure, the error handling is not shown in template.
Steps:
1. Create 2 global boolean flags that will be False by default; one of them
will become True when the “master field” is changed to desired value; the
second will become true when the “dependant field” will be changed.
2. Update flags to False in MoveTo event
3. In FieldChange event, update the first flag to True when the “master field”
is changed to desired value; update the second flag to True when the
dependant field is changed
4. In CanPost event, if the “master field” was changed (ie: the first flag is
True), and the second field was not changed (ie: the second flag is False),
do not allow item posting.
Code Template:
Sub {Mode}_{Object}_MoveTo()
…
b{MasterField}Changed = False
b{DependantField}Changed = False
…
End Sub
Sub {Mode}_{Object}_FieldChange(FieldName)
…
Select Case FieldName
…
Case “{MasterField}”
If {Object}_Fields(“{MasterField}”).Value = {Value} Then
b{MasterField}Changed = True
End If
Case “{DependantField}”
b{DependantField}Changed = True
…
End Select
…
End Sub
Function {Mode}_{Object}_CanPost()
…
If b{MasterField}Changed And _
Not b{DependantField}Changed Then
MsgBox “Please update <” & _
{Object}_Fields(“{DependantField}”).FieldLabel & _
“> field.”, vbCritical + vbOKOnly, _
“Workflow - Field Change Verification”
{Mode}_{Object}_CanPost = False
Else
{Mode}_{Object}_CanPost = True
End If
…
End Function
Template 2.5
Usage Example: In the following example, when the Status field is changed to
“Fixed”, the scripts ensures that R&D Comments field was updated as well.
Sub Defects_Bug_MoveTo()
bStatusChanged = False
bRDCommentsChanged = False
End Sub
Sub Defects_Bug_FieldChange(FieldName)
Select Case FieldName
Case “BG_STATUS”
If Bug_Fields(“BG_STATUS”).Value = “Fixed” Then
bStatusChanged = True
End If
Case “BG_DEV_COMMENTS”
bRDCommentsChanged = True
End Select
End Sub
Function Defects_Bug_CanPost()
If bStatusChanged And Not bRDCommentsChanged Then
MsgBox “Please update <“ & _
Bug_Fields(“BG_DEV_COMMENTS”).FieldLabel & _
“> field.”, vbCritical + vbOKOnly, _
“Workflow – Field Change Verification”
Defects_Bug_CanPost = False
Else
Defects_Bug_CanPost = True
End If
End Function
2.6 Check That the Object Is Not Yet Submitted to the Project (“new
object”)
Purpose: In many cases you need to verify if the object was not yet submitted to
the project. The following code allows to perform such verification. For example: you
want to verify that the new defect is always submitted with the status ‘New’; on test
creation you want to fill some user-defined field; etc.
Code Location: The code should be added in each relevant procedure or function
(when such verification is needed). {Object} should be changed with the name of
the object for which the verification is needed (for example: Bug, Test, etc.); the
{Object ID Field} should be changed to the name of the field stores the ID of the
object (for example: BG_BUG_ID, TS_TEST_ID, etc.).
Templates Used: None
Arguments: Not relevant
Return Value: Not relevant
Usage Example: The example below checks if the defect is “new object”, and
doesn’t allow to post such defect id its status is not “New”:
Sub Defects_Bug_CanPost()
On Error Resume Next
…
If Bug_Fields(“BG_BUG_ID”).Value = “” And _
Bug_Fields(“BG_STATUS”).Value <> “New” Then
MsgBox “The <Status> of the new bug should be ‘New’.”
Defects_Bug_CanPost = False
End If
…
PrintError “Defects_Bug_CanPost”
On Error GoTo 0
End Sub
Code Template:
Dim s{FieldLabel}OrigValue
…
Sub {Mode}_{Object}_MoveTo()
…
s{FieldLabel}OrigValue = {Object}_Fields(“{FieldName}”). Value
…
End Sub
…
Function {Mode}_{Object}_CanPost()
…
If {Condition} Then
{Object}_Fields(“{FieldName}”). Value = s{FieldLabel}OrigValue
End If
…
End Sub
Template 2.7
Usage Example: In the example below when the user sets the status of the defect
to Closed, and doesn’t fill the Closed In Version field, the value of the Status field is
changed back to the original value:
Dim sStatusOrigValue
…
Sub Defects_Bug_MoveTo()
…
sStatusOrigValue = Bug_Fields(“BG_STATUS”).Value
…
End Sub
…
Function Defects_Bug_CanPost()
…
If Bug_Fields(“BG_CLOSING_VERSION”).Value = “” Then
MsgBox “The Closed In Version value was not specified.”, vbCritical
Bug_Fields(“BG_STATUS”).Value = sStatusOrigValue
End If
…
End Function
Code Template:
Function Check{Object}Owner(strFieldNames)
On Error Resume Next
Dim strFieldArr
CheckObjectOwner = False
strFieldArr = Split(strFieldNames, “;”)
For i = 0 To Ubound(strFieldArr)
If {Object}_Fields(strFieldArr(i)).Value = User.UserName Then
CheckObjectOwner = True
End If
Next
PrintError “Check{Object}Owner”
On Error GoTo 0
End Sub
Template 2.8
Usage Example: In the example below 3 fields define the owner of the defect:
BG_DETECTED_BY, BG_RESPONSIBLE and BG_USER_01 (user-defined field with the
User list attached). When the user tries to change defect’s Priority (BG_PRIORITY) or
Severity (BG_SEVERITY), workflow checks if the user is the owner of the defect (ie:
the name of current user appears in one of 3 specified fields). If the user is not the
owner of the object, the field value is reverted to the original value. Note that
template 2.7 is used in this example.
Dim sPriorityOrigValue
Dim sSeverityOrigValue
Sub Defects_Bug_MoveTo
…
sPriorityOrigValue = Bug_Fields(“BG_PRIORITY”).Value
sSeverityOrigValue = Bug_Fields(“BG_SEVERITY”).Value
…
End Sub
Sub Bug_FieldChange(FieldName)
Dim strOwnerFields
strOwnerFields = “BG_DETECTED_BY;BG_RESPONSIBLE;BG_USER_01”
…
Select Case FieldName
Case “BG_SEVERITY”, “BG_PRIORITY”
If Not CheckBugOwner(strOwnerFields) Then
MsgBox “Only owners can change defect Severity and Priority”
Bug_Fields(“BG_PRIORITY”).Value = sPriorityOrigValue
Bug_Fields(“BG_SEVERITY”).Value = sSeverityOrigValue
End If
End Select
…
End Sub
3. Working with TestDirector API (OTA)
3.1 Getting the current connection (current session)
Purpose: The code below shows how to receive the current session context in
workflow (the same session in which the user will work during script execution).
Code Location: The code should be added in each relevant procedure or function
(when the access to OTA is required).
Templates Used: None
Arguments: Not relevant
Return Value: Not relevant
Usage Example: In the example below server time (TDConnection class property) is
shown in message box:
Code Template:
Dim varRes
‘ Returns the current server URL
varRes = TDConnection.ServerName
‘ Returns the current server time (Date type)
varRes = TDConnection.ServerTime
‘ Returns the current domain name
varRes = TDConnection.DomainName
‘ Returns the current project name
varRes = TDConnection.ProjectName
‘ Returns the current project type (Access, Oracle, MS SQL, Sybase)
varRes = TDConnection.ProjectType
‘ Returns the current user name (no need to use TDConnection here – ‘ the
workflow has the predefined object called User)
varRes = User.UserName
‘ Returns the current user password
varRes = TDConnection.Password
Template 3.2
Usage Example: In the example below, the server name is used to verify whether
the user connected to the server using HTTP or HTTPS:
Usage Example: The example below checks if the user belongs to TDAdmin group
If User.IsInGroup(“TDAdmin”) Then
MsgBox “You are the member of TDAdmin group”
Else
MsgBox “You are not the member of TDAdmin group”
End If
Solution 2: Receiving the list of all the groups to which the current user
belongs
Purpose: The code below allows getting the list of all groups to which the current
user belongs.
Code Location: code should be added to the code of each workflow script (Defects,
Test Plan, etc.).
Templates Used: templates 2.1.1, 2.1.2
Arguments: None
Return Value: string that contains the names of the groups to which the user
belongs. The names of the groups are separated by semicolon.
Code Template:
Function GetUserGroups()
Dim objCustomization, objUsers, objUser, objGroup
Dim strGroupList
On Error Resume Next
Set objCustomization = TDConnection.Customization
Set objUsers = objCustomization.Users
Set objUser = objUsers.User(User.UserName)
strGroupList = “”
For Each objGroup In objUser.GroupsList
strGroupList = strGroupList & “;” & objGroup.Name
Next
GetUserGroups = Left(strGroupList, Len(strGroupList)-1)
Set objCustomization = Nothing
Set objUsers = Nothing
Set objUser = Nothing
PrintError "GetUserGroups"
On Error GoTo 0
End Function
Template 3.3
Note: You can use Split function in order to convert the string returned by this
function into array:
Dim strGroupArray
strGroupArray = Split(GetUserGroups, “;”)
Usage Example: in the following example the list of the groups is received using the
template above; the user role is later defined according to the groups. For example if
the user is the member of “QA Tester” team, the user role is defined as “QA”; if the
user is the member of “Managers” and “Developers” groups, then user role is defined
as “R&D Manager” etc.
Dim strFieldArray
strFieldArray = Array(“{Field Name1}”, “{Field Name2}”, …)
Code Template:
Usage Example: in the following example the values of Detected in Version field
(BG_DETECTION_VERSION) and Project field (BG_PROJECT) are saved when the
user submits the new bug. The saved values are retrieved the next time the user
opens Add Defect form.
Sub Defects_Bug_New
On Error Resume Next
…
‘ Retrieve the values of the fields on opening of new bug
KeepLastValue "GET", ""
…
PrintError “Defects_Bug_ New”
On Error GoTo 0
End Sub
Function Defects_Bug_CanPost
On Error Resume Next
Dim strFieldArray
…
‘ Save the values of the fields on submit of new bug
strFieldArray = Array(“BG_DETECTION_VERSION”, "BG_PROJECT")
If Bug_Fields("BG_BUG_ID").Value = "" Then
KeepLastValue "SET", strFieldArray
End If
…
PrintError “Defects_Bug_CanPost”
On Error GoTo 0
End Function
Purpose: The following code template allows sending any object in TestDirector
(Defect, Test, etc.) by e-mail. The code can be used to extend the automatic mail
notifications with custom conditions, not available for Send All Qualified. The
template uses TestDirector mailing functions.
Code Location: The code for the each object should be placed in the script of the
corresponding module. For example: SendDefect function should be placed in
Defects module.
Templates Used: templates 2.1.1, 2.1.2
Arguments:
iObjectId – The ID of the object that should be sent (see the note below on
how to obtain the object ID).
strTo – The TestDirector names or e-mails of the people that will appear in To
field of the e-mail (the names and e-mails should be separated by semicolon.
For example: “[email protected];admin;alice_td”).
strCc – The TestDirector names or e-mails of the people that will appear in Cc
field of the e-mail (the names and e-mails should be separated by semicolon.
For example: “[email protected];admin;alice_td”). Specify an empty string
(“”) to omit this parameter.
strSubject – The e-mail Subject. Specify an empty string (“”) to omit this
parameter.
strComment – The e-mail comment (will appear at the top of the e-mail).
Specify an empty string (“”) to omit this parameter.
Notes:
1. The object ID value can always be retrieved using the {Object}_Fields
collection, by retrieving the Value property of the ID field. The example below
shows how to retrieve the Ids of Defect, Test and Requirement:
Code Template:
Sub TestPlan_Test_FieldChange(FieldName)
On Error Resume Next
Dim strSubject, strComment
If FieldName = "TS_STATUS" Then
strSubject = “Test Change Notification” & _
“ for project “ & TDConnection.ProjectName & _
“ in domain “ & TDConnection.DomainName
strComment = “The user “ & User.FullName & _
“ changed the status of the test ” & _
Test_Fields(“TS_NAME”).Value & _
“ to “ & Test_Fields(“TS_ STATUS”).Value
SendTest Test_Fields("TS_TEST_ID").Value, _
Test_Fields(“TS_RESPONSIBLE”).Value, “[QA Testers]”, _
strSubject, StrComment
End If
On Error GoTo 0
End Sub
Purpose: The template allows obtaining statistics for the user, for example: how
many defects are assigned to current user. The template may be used to create the
button that shows this statistics whenever user clicks on it. Another way to use this
template is to create the conditions that allow the team leader to decide on tasks.
For example: the team leader doesn’t want to allow more then 5 defects with priority
Urgent and with status Open or Reopen to be assigned to one person.
Note: The template below is for the Defects. However such function can be created
for any object in TestDirector.
Code Location: The code for the each object should be placed in the script of the
corresponding module. Each logical set should be placed in separate function as well.
Templates Used: templates 2.1.1, 2.1.2
Arguments:
strFilterConditions – The conditions for which the number of objects should be
found. Should be specified in the format
“FILTER_FIELD2=FilterCondition1; FILTER_FIELD2=FilterCondition2;”
While filter conditions format is the same as the format that is used in
OTAClient for filters.
For example: if you want to get the number of defects assigned to the user
“alex_td”, that have status “Open” or “Reopen” and the priority “4-Urgent”,
the following string should be specified:
“BG_RESPONSIBLE=alex_td;BG_STATUS=Open Or Reopen;BG_PRIORITY=4-
Urgent”
Return Value: Returns the number of objects for given condition
Code Template:
Function GetDefectStatistics(strFilterConditions)
On Error Resume Next
Dim strFilterConditionArr, strCondition
Dim objBugFactory, objFilter, objList
Set objBugFactory = TDConnection.BugFactory
Set objFilter = objBugFactory.Filter
strFilterConditionArr = Split(strFilterConditions, “;”)
For i = 0 To Ubound(strFilterConditionArr)
strCondition = Split(strFilterConditionArr(i), “=”)
If Ubound(strCondition) = 1 Then
objFilter.Filter(strCondition(0)) = strCondition(1)
End If
Next
Set objList = objFilter.NewList
GetDefectStatistics = objList.Count
Set objList = Nothing
Set objBugFactory = Nothing
Set objFilter = Nothing
PrintError “GetDefectStatistics”
On Error GoTo 0
End Function
Template 3.6
Usage Example: In the following example when the defect with priority “4-Urgent”
is assigned to some user, workflow checks how many defects with the same priority
and the status “Open” or “Reopen” are already assigned to the same user. If the
number of defects is 5 or more, the workflow will show warning.
Sub Defects_Bug_FieldChange(FieldName)
On Error Resume Next
Dim strConditions, iNumberOfBugs
If FieldName = "BG_RESPONSIBLE" Then
strConditions = “BG_RESPONSIBLE=” & _
Bug_Fields(“BG_RESPONSIBLE”).Value & _
“;BG_STATUS=Open Or Reopen” & _
“;BG_PRIORITY=4-Urgent”
iNumberOfBugs = Cint(GetDefectStatistics(strConditions))
If iNumberOfBugs >= 5 Then
MsgBox “” & iNumberOfBugs & “ defects” & _
“ with Priority=<4-Urgent> and “ & _
“ Status=<Open> or <Reopen>” & _
“ are already assigned to the user “ & _
Bug_Fields(“BG_RESPONSIBLE”).Value
End If
End If
On Error GoTo 0
End Sub
3.7 Setting the Last Item in List As a Default Value of the Field
Purpose: The template allows to select the last item from the list, and to set it as a
default value for some field. This is useful for the fields where the last value is most
commonly used. For example: the field Detected In Version has a list of versions
attached. Most of the users will select the current version for the defects they
submit, which is the last in the list. So this value can be a default for this field.
Code Location: code should be added to the code of each workflow script (Defects,
Test Plan, etc.). Separate procedures should be created for each object for which this
functionality is needed. The {Object} statement should be replaced with the name of
the object for which the template is used (for example: Bug, Test, etc.).
Templates Used: templates 2.1.1, 2.1.2
Arguments:
strFieldName – The name of the field for which the default value should be
set.
strListName – The name of the list from which the default value should be
selected. This list should be attached to the field specified by strFieldName.
Return Value: None
Code Template:
Usage Example: In the following example when the New Defect form is opened, the
script assigns “Versions” list to Detected in Version (BG_DETECTION VERSION) field.
Then the value of the Detected In Version field is set to the last item in Versions list.
Sub Defects_Bug_New()
On Error Resume Next
Bug_Fields(“BG_DETECTION_VERSION”).List = Lists(“Versions”)
SetDefaultValue(“BG_DETECTION_VERSION”, “Versions”)
On Error GoTo 0
End Sub
Purpose: The template allows copying the value from last test run to test in test set.
For example: each time the test is executed, the user wants the value of Duration
field of the run to be copied to the Expected Duration user-defined field of test in test
set.
Code Location: code should be added to the code of Test Lab workflow script
Templates Used: templates 2.1.1, 2.1.2
Arguments:
strSrcRunField – The name of the Run field from which the value should be
copied.
strTrgTSTestField – The name of the Test in Test Set field to which the value
should be copied.
Return Value: None
Code Template:
Usage Example: In the following example the user has Expected Duration field for
Test in Test Set (TC_USER_01). The value of this field is updated any time the value
of Duration field (RN_DURATION) of the last run differs from Expected Duration of
the test.
Sub TestLab_TestSetTests_MoveTo
On Error Resume Next
CopyLastRunValue "TC_USER_01", "RN_DURATION"
On Error GoTo 0
End Sub