cunderw's avatar
cunderw
Community Hero
9 years ago
Status:
New Idea

More Access To Project Test Items Info

It would be great to have an event listener for OnProjectEnd, and / or the number of enabled test items.

 

The scenario that makes not having this a huge PIA is if you want to send an email summary at the end of  an entire Project Run with several test items.

 

The work around needed to do this required using the OnTestStop event to increment my own counter for the number of tests ran, export the logs and build the body of the email from that.

 

To email only at the end of the Project Run, I had to make sure that my number of tests ran counter was equal to the number of enabled test items. 

 

To ge tthe number of enabled test items requires looping through all test items using recursion at the start of the test. 

2 Comments

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3

    Hi,

     

    While I agree with your request, check if the following functions can be of any help.

     

    '-----------------------------------------------------------------------------

    ' From: http://www.automatedqa.com/forums/forum/post/?mode=singleThread&thread=c5788c98-32ee-4d52-b6c7-ea7347d6ab07
    ' Code that counts errors and warnings
    ' Note that if you run a project, you need to get the summary of errors and
    ' warnings using the GetSum function in a routine (in this case, it is PostSum)
    ' set as the last test item of the project. If you run a project suite,
    ' you need to add a project to the end of the test item list of the project suite.
    ' This project should contain the only test item calling the routine that uses the GetSum function.
    Function LogGetErrorsSum(logFolder) ' : OleVariant;
    Const cProcName = "LogGetErrorsSum"
    Dim cProcNameMsgPrefix : cProcNameMsgPrefix = cUnitNameMsgPrefix & cProcName & "(): "

    Dim itemsInfo : itemsInfo = BuiltIn.CreateVariantArray(0, 1) ' errorsCount, warningsCount
    Dim tempFolder, xDoc
    Dim wrnC, errC

    itemsInfo(0) = -1
    itemsInfo(1) = -1

    tempFolder = logFolder

    Set xDoc = Sys.OleObject("MSXML2.DOMDocument")
    xDoc.load(tempFolder & "Description.tcLog")

    ' Warning count
    wrnC = VarToInteger(xDoc.selectSingleNode( _
    "Nodes/Node[@name='root']/Prp[@name='warning count']/@value").text)
    itemsInfo(1) = wrnC

    ' Error count
    errC = VarToInteger(xDoc.selectSingleNode( _
    "Nodes/Node[@name='root']/Prp[@name='error count']/@value").text)
    itemsInfo(0) = errC

    LogGetErrorsSum = itemsInfo
    End Function
    '-----------------------------------------------------------------------------

    Function LogGetSummaryInfo(logFolder) ' : OleVariant;
    Const cProcName = "LogGetSummaryInfo"
    Dim cProcNameMsgPrefix : cProcNameMsgPrefix = cUnitNameMsgPrefix & cProcName & "(): "

    Dim itemsInfo : itemsInfo = BuiltIn.CreateVariantArray(0, 3) ' total, executed, passed, failed
    Dim tempFolder, xDoc, rootItem, summaryNode

    itemsInfo(0) = -1
    itemsInfo(1) = -1
    itemsInfo(2) = -1
    itemsInfo(3) = -1

    tempFolder = aqFileSystem.IncludeTrailingBackSlash(logFolder)

    Set xDoc = Sys.OleObject("MSXML2.DOMDocument")
    xDoc.load(tempFolder & "RootLogData.dat")

    ' find the name of the file with the root log node
    rootItem = xDoc.selectSingleNode("Nodes/Node/Node[@name='item 0']/Prp[@name='filename']/@value").text

    xDoc.load(tempFolder & rootItem)

    ' find the summary node
    Set summaryNode = xDoc.selectSingleNode("Nodes/Node/Node[@name='summary']")
    If (summaryNode.hasChildNodes) Then
    ' commented line fails for some reason with this error:
    ' Unknown method. Node[@name='total']/Prp[-->starts-with(@<--name, 'total')]/@value
    ' http://stackoverflow.com/questions/10801399/how-to-select-nodes-by-attribute-that-starts-with-in-c-sharp
    ' http://support2.microsoft.com/kb/303516
    ' itemsInfo(0) = VarToInteger(summaryNode.selectSingleNode("Node[@name='total']/Prp[starts-with(@name, 'total')]/@value").text)
    itemsInfo(0) = VarToInteger(summaryNode.selectSingleNode("Node[@name='total']/Prp[@name='total (sum)']/@value").text)
    itemsInfo(1) = VarToInteger(summaryNode.selectSingleNode("Node[@name='executed']/Prp[@name='total (sum)']/@value").text)
    itemsInfo(2) = VarToInteger(summaryNode.selectSingleNode("Node[@name='passed']/Prp[@name='total (sum)']/@value").text)
    itemsInfo(3) = VarToInteger(summaryNode.selectSingleNode("Node[@name='failed']/Prp[@name='total (sum)']/@value").text)
    End If

    LogGetSummaryInfo = itemsInfo
    End Function
    '-----------------------------------------------------------------------------

    ' Function counts the number of groups and testitems (enabled/disabled) in the project
    ' From: http://www.automatedqa.com/forums/forum/post/?mode=singleThread&thread=609e4fae-3925-40d2-b637-20a53f993681
    Function LogGetTestItemsInfo(testItems) ': integer;
    Const cProcName = "LogGetTestItemsInfo"
    Dim cProcNameMsgPrefix : cProcNameMsgPrefix = cUnitNameMsgPrefix & cProcName & "(): "

    Dim itemsInfo : itemsInfo = BuiltIn.CreateVariantArray(0, 2) ' groupsCount, itemsCount, enabledItemsCount
    Dim i, testItem
    Dim childItemsInfo : childItemsInfo = BuiltIn.CreateVariantArray(0, 2) ' groupsCount, itemsCount, enabledItemsCount

    itemsInfo(0) = 0
    itemsInfo(1) = 0
    itemsInfo(2) = 0

    For i = 0 To testItems.ItemCount - 1
    Set testItem = testItems.TestItem(i)
    If (testItem.ElementToBeRun Is Nothing) Then _
    itemsInfo(0) = itemsInfo(0) + 1

    If (testItem.ItemCount <> 0) Then
    childItemsInfo = LogGetTestItemsInfo(testItem)
    itemsInfo(0) = itemsInfo(0) + childItemsInfo(0)
    itemsInfo(1) = itemsInfo(1) + childItemsInfo(1)
    If (testItem.Enabled) Then _
    itemsInfo(2) = itemsInfo(2) + childItemsInfo(2)
    Else
    itemsInfo(1) = itemsInfo(1) + 1
    If (testItem.Enabled) Then _
    itemsInfo(2) = itemsInfo(2) + 1
    End If
    Next ' i
    LogGetTestItemsInfo = itemsInfo
    End Function
    '-----------------------------------------------------------------------------

    Sub LogPostSummaryInfoDynamic
    Const cProcName = "SysMappingRecordsetGetValue"
    Dim cProcNameMsgPrefix : cProcNameMsgPrefix = cUnitNameMsgPrefix & cProcName & "(): "

    Dim itemsInfo : itemsInfo = BuiltIn.CreateVariantArray(0, 3) ' total, executed, passed, failed
    Dim itemsErrorsInfo : itemsErrorsInfo = BuiltIn.CreateVariantArray(0, 1) ' errorsCount, warningsCount
    Dim itemsProjectInfo : itemsProjectInfo = BuiltIn.CreateVariantArray(0, 2) ' groupsCount, itemsCount, enabledItemsCount
    Dim tempFolder

    tempFolder = aqString.Format("%s~TC%s\", _
    aqFileSystem.IncludeTrailingBackSlash( _
    aqEnvironment.GetEnvironmentVariable("temp")), _
    aqConvert.DateTimeToFormatStr(aqDateTime.Now, "%Y%m%d_%H%M%S"))

    Call aqFileSystem.CreateFolder(tempFolder)

    Call Log.SaveResultsAs(tempFolder, lsXML)

    itemsInfo = LogGetSummaryInfo(tempFolder)
    itemsErrorsInfo = LogGetErrorsSum(tempFolder)
    itemsProjectInfo = LogGetTestItemsInfo(Project.TestItems)

    Call aqFileSystem.DeleteFolder(tempFolder, True)

    Call Log.Message("Test Summary Information (see Additional Info log tab)", _
    "Total number of test items been ran: " & VarToStr(itemsInfo(0)) & vbCrLf & _
    "Executed project test items: " & VarToStr(itemsInfo(1)) & _
    aqString.Format(" (%.2f%%)", VarToInt(itemsInfo(1)) / VarToInt(itemsInfo(0)) * 100) & vbCrLf & _
    "Project test items executed successfully: " & VarToStr(itemsInfo(2)) & _
    aqString.Format(" (%.2f%%)", VarToInt(itemsInfo(2)) / VarToInt(itemsInfo(1)) * 100) & vbCrLf & _
    "Failed project test items: " & VarToStr(itemsInfo(3)) & _
    aqString.Format(" (%.2f%%)", VarToInt(itemsInfo(3)) / VarToInt(itemsInfo(1)) * 100) & vbCrLf & _
    "Errors count: " & VarToStr(itemsErrorsInfo(0)) & vbCrLf & _
    "Warnings count: " & VarToStr(itemsErrorsInfo(1)) & vbCrLf & _
    vbCrLf & _
    "# of Test Item Groups (total): " & VarToStr(itemsProjectInfo(0)) + vbCrLf & _
    "Project Test Items (total): " & VarToStr(itemsProjectInfo(1)) + vbCrLf & _
    "Enabled Project Test Items (total): " & VarToStr(itemsProjectInfo(2)) & _
    aqString.Format(" (%.2f%%)", VarToInt(itemsProjectInfo(2)) / VarToInt(itemsProjectInfo(1)) * 100) _
    )
    End Sub
    '-----------------------------------------------------------------------------

  • cunderw's avatar
    cunderw
    Community Hero

    That's actually very simlar to what I did. It's just a pain that it has to be done this way IMO

     

    Here is how I did it. Note, it's more specfic to our needs.

     

     

     

    var runCount = 0;
    var totalTests = getNumEnabledTests(Project.TestItems);
    function GeneralEvents_OnStopTest(Sender) {
      if (Project.Variables.postRunEnabled) {
          // exports and emails log summary
          runCount++;
          try {
            BuildAndSendLogs();
          }
          catch(err) {
            Log.Warning(err);        
          }
      }
      else {
        Log.Message("PostRun Disabled");
      }
    }
    
    function BuildAndSendLogs() {
      // checks if a test passed or failed and sets status for email subject
      var testStatus = GetTestStatus();
      if (testStatus == "FAILED") {
        projectStatus = "FAILED";
      }
      
      // builds email body
      emailBody += "\n\n" + GetLogItems();    
      // if all tests have ran, send the email
      if (runCount == totalTests) {
        emailBody += "\n\nEnd Time: " + aqDateTime.Now(); 
        emailSubject += " " + projectStatus;
        try {
          if (SendMail(emailAddressTo, emailServer, emailWho, emailAddressSender, emailSubject, emailBody)) 
            Log.Message("Mail was sent");
          else 
            Log.Warning("Mail was not sent");
        }
        catch(err) {
          Log.Warning("Error building email and sending: " + err);
        }
      }
    }
    
    function GetLogItems() {
      // creates a random temp folder to export the logs too
      var tempFolder = aqEnvironment.GetEnvironmentVariable("temp") + "\\" + 
                        GetTickCount() + "\\";
      if (0 != aqFileSystem.CreateFolder(tempFolder)) {
        Log.Error("The " + tempFolder + " temp folder was not created");
        return "";
      }
      // exports the log to the created folder
      if (!Log.SaveResultsAs(tempFolder, lsHTML, false, 2)) {
        Log.Error("Log was not exported to the " + tempFolder + " temp folder");
        return "";
      }
      // loads the xml from the xpoerted log
      var xDoc = Sys.OleObject("MSXML2.DOMDocument.4.0");
      xDoc.load(tempFolder + "root.xml");
      // calls logdatatext with the needed node from the xml file                                            
      var result = LogDataToText(xDoc.childNodes.item(1), 0, "  ");
      // deletes temp folder
      aqFileSystem.DeleteFolder(tempFolder, true);
      return result;   
    }
     
    function LogDataToText(logData, indentIndex, indentSymbol) {
      // if this doesn't match it means something was not exported correct so it returns empty string
      if ("LogData" != logData.nodeName) {
        return "";
      }
      var result = "";
      for(var i = 0; i < indentIndex; i++) {
        result += indentSymbol;
      }
      result = result + "Name: " + logData.getAttribute("name") + indentSymbol + "Status:" + indentSymbol + 
                GetTextOfStatus(logData.getAttribute("status")) + "\r\n";
      for(var i = 0; i < logData.childNodes.length; i++) {
        result += LogDataToText(logData.childNodes.item(i), indentIndex + 1, indentSymbol);
      }
      return result;
    }
     
    function GetTextOfStatus(statusIndex) {
    // returns text for a status code
      switch(statusIndex) {
        case "0": return "PASSED";
        case "1": return "WARNING";
        case "2": return "FAILED";
        default: return "UNDEFINED";
      }
    }
    
    function GetTestStatus() {
    // returns status code
      var result;
      var tempFolder = aqEnvironment.GetEnvironmentVariable("temp") + "\\" + 
                        GetTickCount() + "\\";
      if (0 != aqFileSystem.CreateFolder(tempFolder)) {
        Log.Error("The " + tempFolder + " temp folder was not created");
        return "";
      }
      if (!Log.SaveResultsAs(tempFolder, lsHTML, false, 2)) {
        Log.Error("Log was not exported to the " + tempFolder + " temp folder");
        return "";
      }
      var xDoc = Sys.OleObject("MSXML2.DOMDocument.4.0");
      xDoc.load(tempFolder + "root.xml");
      var logData = xDoc.childNodes.item(1);
      result = GetTextOfStatus(logData.getAttribute("status"));
      aqFileSystem.DeleteFolder(tempFolder, true);
      return result;   
    }
    
    
    function getNumEnabledTests(testItems) {
      if(getNumEnabledTests.enabledCount == undefined) {
        getNumEnabledTests.enabledCount = 0;
      }
      var itemCount = testItems.ItemCount;
      
    // buids total tests based on if they are enabled.
    // note this is super hacky, but I dunno how else to get it
      for(var i = 0; i < itemCount; i++) {
        if(testItems.TestItem(i).Enabled) {
          if(testItems.TestItem(i).ElementToBeRun != null) {
            getNumEnabledTests.enabledCount++;
          }
          if(testItems.TestItem(i).ItemCount != 0) {
            getNumEnabledTests(testItems.TestItem(i));
          }
        }
      }
      return getNumEnabledTests.enabledCount;
    }