MSTest or TRX to HTML with Animated Charts





5.00/5 (11 votes)
MS Test Result Viewer is a free open source library to convert MS Test result (.trx) file into HTML. It is also allowed you to perform MS Test on your test container project (.dll) file. This utility will work with simple command line arguments to generate test report in HTML format with excellent U
Animated Test Result Charts | Test Result Error Window | Print Report |
![]() | ![]() | ![]() |
Introduction
This tool will allows you to generate HTML report as well as you can perform MS Test on your test project container. This provides a number of advantages like, It allows for easy state management in your tests. Your setup and tear down code will be run each time a method is called and your instance variables are automatically reset. There’s no need to reset them manually as it is in NUnit. Indeed, many of MSTest’s other strengths rely on this very principle as we shall see.
About MSTest from Microsoft's site.
"MSTest.exe is the command-line command that is used to run tests. This command has several options you can use to customize your test run. You can use many of these options in conjunction with one another; in fact, you must use certain options in conjunction with others, as described in the following sections. You can specify these options in any order on the MSTest.exe command line."
for more detail: http://msdn.microsoft.com/en-us/library/ms182489%28v=vs.80%29.aspx
Using the code
- Prerequisite
- RGraph (http://www.rgraph.net)
- jQuery UI Layout Plug-in (http://layout.jquery-dev.net)
- jQuery Grid Plugin – jqGrid (http://www.trirand.net)
- MS Test (http://msdn.microsoft.com/en-us/library/ms182489%28v=vs.80%29.aspx)
- Class Hierarchy
- Variable Declaration Defined constants for TableName, Columns, Tags, Attributes and ExecutionSleep as well as some variables are defined for access in more than one methods.
#region "Variables"
const int SLEEP_EXECUTION_TIME = 200;
const string TAG_UNITTEST = "UnitTest";
const string TAG_ERRORINFO = "ErrorInfo";
const string TABLE_TESTMETHOD = "TestMethod";
const string TABLE_TESTRUN = "TestRun";
const string TABLE_UNITTESTRESULT = "UnitTestResult";
const string TABLE_TIMES = "Times";
const string COLUMN_CLASSNAME = "className";
const string COLUMN_NAME = "name";
const string COLUMN_RUNUSER = "runUser";
const string COLUMN_MESSAGE = "Message";
const string COLUMN_STACKTRACE = "StackTrace";
const string COLUMN_COUNTERS = "Counters";
const string COLUMN_TOTAL = "total";
const string COLUMN_PASSED = "passed";
const string COLUMN_FAILED = "failed";
const string COLUMN_INCONCLUSIVE = "inconclusive";
const string COLUMN_TESTNAME = "testName";
const string COLUMN_OUTCOME = "outcome";
const string COLUMN_DURATION = "duration";
const string COLUMN_CREATION = "creation";
const string COLUMN_CODEBASE = "codebase";
const string ATTRIBUTE_TESTMETHODID = "TestMethodID";
const string ATTRIBUTE_ID = "id";
const string ATTRIBUTE_TESTID = "testId";
const string FILENAME_TRX = "MSTestResult.trx";
private static TestEnvironmentInfo testEnvironmentInfo;
private static TestResultSummary testResultSummary;
private static List<TestProjects> testProjects;
static string projectChartDataValue = "";
static string classChartDataValue = "";
static string classChartDataText = "";
static string methoChartDataValue = "";
static string methoChartDataText = "";
static string methoChartDataColor = "";
static string folderPath = "";
static string trxFilePath = "";
static string MSTestExePathParam = "";
static string TestContainerFolderPathParam = "";
static string DestinationFolderParam = "";
static string LogFileParam = "";
static string HelpFileParam = "";
#endregion
- Properties To get Application Name and Version number for displaying on HTML Report.
public static string Title
{
get { return GetValue<AssemblyTitleAttribute>(a => a.Title); }
}
public static string Version
{
get { return "1.0"; }
}
static string GetValue<T>(Func<T, string> getValue) where T : Attribute
{
T a = (T)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(T));
return a == null ? "" : getValue(a);
}
Name | Flag | Summary |
MSTest Exe File Path | /m |
You have to define physical path of MSTest.exe. this will required only if you don’t have .trx file. |
Test Container Folder Path | /tc |
You have to define physical path of your test container file (.dll). this will required only if you don’t have .trx file. |
Trx File Path | /t | You have to define physical path of trx file. |
Destination Folder Path | /d | Output data (HTML) files will store at this location. If path not exists then it will automatically created. |
Help | ? | This will display all command parameters on screen |
- Command Line Usage
MSTestResultViewer.Consol.exe /t "d:\test.trx" /d "d:\HTMLReport"
- Transform This method will fill dataset using xml file, and then dataset will use for calculating all the statistics and information for Test cases and environmental details.
private static void Transform(string fileName)
{
XmlDocument xmlDoc = new XmlDocument();
if (File.Exists(fileName))
{
xmlDoc.Load(fileName);
XmlNodeList list = xmlDoc.GetElementsByTagName(TAG_UNITTEST);
foreach (XmlNode node in list)
{
XmlAttribute newAttr = xmlDoc.CreateAttribute(ATTRIBUTE_TESTMETHODID);
newAttr.Value = node.Attributes[ATTRIBUTE_ID].Value;
node.ChildNodes[1].Attributes.Append(newAttr);
}
list = xmlDoc.GetElementsByTagName(TAG_ERRORINFO);
foreach (XmlNode node in list)
{
XmlAttribute newAttr = xmlDoc.CreateAttribute(ATTRIBUTE_TESTMETHODID);
newAttr.Value = (((node).ParentNode).ParentNode).Attributes[ATTRIBUTE_TESTID].Value;
node.Attributes.Append(newAttr);
}
//xmlDoc.Save(fileName);
DataSet ds = new DataSet();
ds.ReadXml(new XmlNodeReader(xmlDoc));
if (ds != null && ds.Tables.Count >= 4)
{
Console.WriteLine(string.Format("Start gathering test environment information...\n"));
System.Threading.Thread.Sleep(SLEEP_EXECUTION_TIME);
SetTestEnvironmentInfo(ds);
Console.WriteLine(string.Format("Start gathering test result summary...\n"));
System.Threading.Thread.Sleep(SLEEP_EXECUTION_TIME);
SetTestResultSummary(ds);
Console.WriteLine(string.Format("Start gathering test classes methods information...\n"));
System.Threading.Thread.Sleep(SLEEP_EXECUTION_TIME);
SetTestClassMethods(ds);
if (testProjects.Count >= 1)
{
Console.WriteLine(string.Format("Start transforming test result into html...\n"));
System.Threading.Thread.Sleep(SLEEP_EXECUTION_TIME);
CreateTestHierarchy();
CreateTestResultTable();
CreateTestResultChart();
Console.WriteLine(string.Format("TRX file transformation completed successfully. \nFile generated at: \"{0}.htm\"\n", trxFilePath));
}
else
{
Console.WriteLine(string.Format("No test cases are available for test\n"));
Console.ReadLine();
}
}
else
{
Console.WriteLine(string.Format("No test cases are available for test\n"));
Console.ReadLine();
}
}
else
{
Console.WriteLine(string.Format("Test Result File (.trx) not found at \"" + trxFilePath + "\"!\n"));
Console.ReadLine();
}
}
private static void SetTestEnvironmentInfo(DataSet ds)
{
DataRow dr = ds.Tables[TABLE_TESTRUN].Rows[0];
string trxfile = dr[COLUMN_NAME].ToString();
int idxattherate = trxfile.IndexOf("@") + 1;
int idxspace = trxfile.IndexOf(" ");
string machine = trxfile.Substring(idxattherate, idxspace - idxattherate);
DateTime time = (ds.Tables[TABLE_TIMES] != null && ds.Tables[TABLE_TIMES].Rows.Count > 0) ? Convert.ToDateTime(ds.Tables[TABLE_TIMES].Rows[0][COLUMN_CREATION]) : DateTime.Now;
string codebase = (ds.Tables[TABLE_TESTMETHOD] != null && ds.Tables[TABLE_TESTMETHOD].Rows.Count > 0) ? ds.Tables[TABLE_TESTMETHOD].Rows[0][COLUMN_CODEBASE].ToString() : "";
testEnvironmentInfo = new TestEnvironmentInfo()
{
MachineName = machine,
OriginalTRXFile = trxfile,
TestCodebase = codebase,
UserName = dr[COLUMN_RUNUSER].ToString(),
Timestamp = time
};
}
private static void SetTestResultSummary(DataSet ds)
{
DataRow dr = ds.Tables[COLUMN_COUNTERS].Rows[0];
testResultSummary = new TestResultSummary()
{
Total = Convert.ToInt16(dr[COLUMN_TOTAL].ToString()),
Passed = Convert.ToInt16(dr[COLUMN_PASSED].ToString()),
Failed = Convert.ToInt16(dr[COLUMN_FAILED].ToString()),
Ignored = Convert.ToInt16(dr[COLUMN_INCONCLUSIVE].ToString()),
Duration = "--",
TestEnvironment = testEnvironmentInfo
};
}
private static void SetTestClassMethods(DataSet ds)
{
DataView view = new DataView(ds.Tables[TABLE_TESTMETHOD]);
DataTable distinctValues = view.ToTable(true, COLUMN_CLASSNAME);
char[] delimiters = new char[] { ',' };
//Getting Distinct Project
testProjects = new List<TestProjects>();
foreach (DataRow dr in distinctValues.Rows)
{
string _project = dr[COLUMN_CLASSNAME].ToString().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)[1].Trim();
int cnt = (from t in testProjects where t.Name == _project select t).Count();
if (cnt == 0) testProjects.Add(new TestProjects() { Name = _project.Trim() });
}
//Iterate through all the projects for getting its classes
foreach (TestProjects project in testProjects)
{
DataRow[] classes = distinctValues.Select(COLUMN_CLASSNAME + " like '% " + project.Name + ", %'");
if (classes != null && classes.Count() > 0)
{
project.Classes = new List<TestClasses>();
foreach (DataRow dr in classes)
{
string _class = dr[COLUMN_CLASSNAME].ToString().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)[0].Trim();
project.Classes.Add(new TestClasses() { Name = _class });
}
}
}
//Iterate through all the projects and then classes to get test methods details
TimeSpan durationProject = TimeSpan.Parse("00:00:00.00");
foreach (TestProjects _project in testProjects)
{
Int32 _totalPassed = 0;
Int32 _totalFailed = 0;
Int32 _totalIgnored = 0;
foreach (TestClasses _class in _project.Classes)
{
TimeSpan durationClass = TimeSpan.Parse("00:00:00.00");
DataRow[] methods = ds.Tables[TABLE_TESTMETHOD].Select(COLUMN_CLASSNAME + " like '" + _class.Name + ", " + _project.Name + ", %'");
if (methods != null && methods.Count() > 0)
{
_class.Methods = new List<TestClassMethods>();
Int32 _passed = 0;
Int32 _failed = 0;
Int32 _ignored = 0;
foreach (DataRow dr in methods)
{
TimeSpan durationMethod = TimeSpan.Parse("00:00:00.00");
TestClassMethods _method = GetTestMethodDetails(ds, dr[ATTRIBUTE_TESTMETHODID].ToString());
switch (_method.Status.ToUpper())
{
case "PASSED":
_passed++;
break;
case "FAILED":
_failed++;
break;
default:
_ignored++;
break;
}
_class.Passed = _passed;
_class.Failed = _failed;
_class.Ignored = _ignored;
_class.Total = (_passed + _failed + _ignored);
_class.Methods.Add(_method);
durationClass += TimeSpan.Parse(_method.Duration);
}
}
_totalPassed += _class.Passed;
_totalFailed += _class.Failed;
_totalIgnored += _class.Ignored;
_class.Duration = durationClass.ToString();
durationProject += TimeSpan.Parse(_class.Duration);
}
_project.Passed = _totalPassed;
_project.Failed = _totalFailed;
_project.Ignored = _totalIgnored;
_project.Total = (_totalPassed + _totalFailed + _totalIgnored);
_project.Duration = durationProject.ToString();
durationProject += TimeSpan.Parse(_project.Duration);
}
}
private static TestClassMethods GetTestMethodDetails(DataSet ds, string testID)
{
TestClassMethods _method = null;
DataRow[] methods = ds.Tables[TABLE_UNITTESTRESULT].Select(ATTRIBUTE_TESTID + "='" + testID + "'");
if (methods != null && methods.Count() > 0)
{
_method = new TestClassMethods();
foreach (DataRow dr in methods)
{
_method.Name = dr[COLUMN_TESTNAME].ToString();
_method.Status = dr[COLUMN_OUTCOME].ToString();//(Enums.TestStatus)Enum.Parse(typeof(Enums.TestStatus), dr[COLUMN_OUTCOME].ToString());
_method.Error = GetErrorInfo(ds, testID);
_method.Duration = dr[COLUMN_DURATION].ToString();
}
}
return _method;
}
private static ErrorInfo GetErrorInfo(DataSet ds, string testID)
{
ErrorInfo _error = null;
DataRow[] errorMethod = ds.Tables[TAG_ERRORINFO].Select(ATTRIBUTE_TESTMETHODID + "='" + testID + "'");
if (errorMethod != null && errorMethod.Count() > 0)
{
_error = new ErrorInfo();
string[] delimiters = new string[] { ":line " };
foreach (DataRow dr in errorMethod)
{
_error.Message = dr[COLUMN_MESSAGE].ToString();
_error.StackTrace = dr[COLUMN_STACKTRACE].ToString();
string strLineNo = _error.StackTrace.Split(delimiters, StringSplitOptions.RemoveEmptyEntries)[1];
Int32 LineNo = Convert.ToInt32(strLineNo);
_error.LineNo = LineNo;
}
}
return _error;
}
private static void CreateTestHierarchy()
{
StringBuilder sb = new StringBuilder();
sb.Append("var treeData = '");
foreach (var _project in testProjects)
{
sb.Append("<li><span class=\"testProject\">" + _project.Name + "</span>");
sb.Append("<ul>");
foreach (var _class in _project.Classes)
{
//Remove project name from name space if exists.
string classname = _class.Name;
string projectname = _project.Name + ".";
string[] tmp = _class.Name.Split(new string[] { projectname }, StringSplitOptions.RemoveEmptyEntries);
if (tmp.Length >= 2)
classname = (tmp[0] == _project.Name) ? ConvertStringArrayToString(tmp, 1) : tmp[0];
else if (tmp.Length == 1)
classname = tmp[0];
sb.Append("<li><span class=\"testClass\">" + classname + "</span>");
sb.Append("<ul>");
foreach (var _method in _class.Methods)
{
string imgStatus = "StatusFailed";
switch (_method.Status)
{
case "Passed":
imgStatus = "StatusPassed";
break;
case "Ignored":
imgStatus = "StatusIngnored";
break;
case "Failed":
imgStatus = "StatusFailed";
break;
}
sb.Append("<li><span class=\"testMethod\">" + _method.Name + "<img src=\"Images/" + imgStatus + ".png\" height=\"10\" width=\"10\" /></span></li>");
}
sb.Append("</ul>");
sb.Append("</li>");
}
sb.Append("</ul>");
sb.Append("</li>");
}
sb.Append("';");
string htmlTestHierarchy = sb.ToString();
WriteFile("TestHierarchy.js", htmlTestHierarchy);
}
private static string ConvertStringArrayToString(string[] array, int startIndex)
{
StringBuilder builder = new StringBuilder();
for (int i = startIndex; i < array.Length; i++)
{
builder.Append(array[i]);
}
return builder.ToString();
}
While clicking on any test method a Error Window (at Bottom side of page) will appear with complete error information.
Again this method will create a dynamic javascript file (Table.js) to display data in TreeGrid format.
private static void CreateTestResultTable()
{
try
{
StringBuilder sbenv = new StringBuilder();
sbenv.Append("var environment = {");
sbenv.Append("'TestCodebase':'" + testEnvironmentInfo.TestCodebase + "',");
sbenv.Append("'Timestamp':'" + testEnvironmentInfo.Timestamp + "',");
sbenv.Append("'MachineName':'" + testEnvironmentInfo.MachineName + "',");
sbenv.Append("'UserName':'" + testEnvironmentInfo.UserName + "',");
sbenv.Append("'OriginalTRXFile':'" + testEnvironmentInfo.OriginalTRXFile + "'");
sbenv.Append("};");
WriteFile("Environment.js", sbenv.ToString());
StringBuilder sb = new StringBuilder();
sb.Append("$(function () {");
sb.Append(" $('#dvTestCodebase').text(environment.TestCodebase);");
sb.Append(" $('#dvGeneratedDate').text(environment.Timestamp);");
sb.Append(" $('#dvMachineName').text(environment.MachineName);");
sb.Append(" $('#dvUserName').text(environment.UserName);");
sb.Append(" $('#dvTRXFileName').text(environment.OriginalTRXFile);");
sb.Append("var mydata = [");
int counter = 0;
foreach (var _project in testProjects)
{
counter++;
int total = _project.Passed + _project.Failed + _project.Ignored;
double percentPass = (_project.Passed * 100);
if (percentPass > 0) percentPass = percentPass / total;
double percentFail = (_project.Failed * 100);
if (percentFail > 0) percentFail = percentFail / total;
double percentIgnore = (_project.Ignored * 100);
if (percentIgnore > 0) percentIgnore = percentIgnore / total;
string strPercent = string.Format("{0},{1},{2}", percentPass, percentFail, percentIgnore);
string strProject = string.Format("{{id: \"{0}\", parent: \"{1}\", level: \"{2}\", Name: \"{3}\", Passed: \"{4}\", Failed: \"{5}\", Ignored: \"{6}\", Percent: \"{7}\", Progress: \"{8}\", Time: \"{9}\", Message: \"{10}\", StackTrace: \"{11}\", LineNo: \"{12}\", isLeaf: {13}, expanded: {14}, loaded: {15}}},", counter, "", "0", _project.Name, _project.Passed, _project.Failed, _project.Ignored, string.Format("{0:00.00}", percentPass), strPercent, TimeSpan.Parse(_project.Duration).TotalMilliseconds, "", "", "", "false", "true", "true");
sb.Append(strProject);
int projParent = counter;
projectChartDataValue = "var projectData = [" + _project.Passed + ", " + _project.Failed + ", " + _project.Ignored + "];";
foreach (var _class in _project.Classes)
{
counter++;
total = _class.Passed + _class.Failed + _class.Ignored;
percentPass = (_class.Passed * 100);
if (percentPass > 0) percentPass = percentPass / total;
percentFail = (_class.Failed * 100);
if (percentFail > 0) percentFail = percentFail / total;
percentIgnore = (_class.Ignored * 100);
if (percentIgnore > 0) percentIgnore = percentIgnore / total;
strPercent = string.Format("{0},{1},{2}", percentPass, percentFail, percentIgnore);
//Remove project name from name space if exists.
string classname = _class.Name;
string projectname = _project.Name + ".";
string[] tmp = _class.Name.Split(new string[] { projectname }, StringSplitOptions.RemoveEmptyEntries);
if (tmp.Length >= 2)
classname = (tmp[0] == _project.Name) ? ConvertStringArrayToString(tmp, 1) : tmp[0];
else if (tmp.Length == 1)
classname = tmp[0];
string strClass = string.Format("{{id: \"{0}\", parent: \"{1}\", level: \"{2}\", Name: \"{3}\", Passed: \"{4}\", Failed: \"{5}\", Ignored: \"{6}\", Percent: \"{7}\", Progress: \"{8}\", Time: \"{9}\", Message: \"{10}\", StackTrace: \"{11}\", LineNo: \"{12}\", isLeaf: {13}, expanded: {14}, loaded: {15}}},", counter, projParent, "1", classname, _class.Passed, _class.Failed, _class.Ignored, string.Format("{0:00.00}", percentPass), strPercent, TimeSpan.Parse(_class.Duration).TotalMilliseconds, "", "", "", "false", "true", "true");
sb.Append(strClass);
int classParent = counter;
classChartDataValue += "[" + _class.Passed + ", " + _class.Failed + ", " + _class.Ignored + "],";
classChartDataText += "'" + classname + "',";
foreach (var _method in _class.Methods)
{
counter++;
int _passed = 0;
int _failed = 0;
int _ignored = 0;
percentPass = 0.0;
strPercent = "";
methoChartDataValue += TimeSpan.Parse(_method.Duration).TotalMilliseconds + ",";
methoChartDataText += "'" + _method.Name + "',";
switch (_method.Status)
{
case "Passed":
_passed = 1;
percentPass = 100;
strPercent = "100,0,0";
methoChartDataColor += "testResultColor[0],";
break;
case "Failed":
_failed = 1;
strPercent = "0,100,0";
methoChartDataColor += "testResultColor[1],";
break;
case "Ignored":
_ignored = 1;
strPercent = "0,0,100";
methoChartDataColor += "testResultColor[2],";
break;
}
string strError = "";
string strStack = "";
string strLine = "";
if (_method.Error != null)
{
strError = _method.Error.Message.Replace("\r\n", "").Replace("\"", "'");
strStack = _method.Error.StackTrace.Replace("\r\n", "").Replace("\"", "'");
strLine = _method.Error.LineNo.ToString();
}
string strMethod = string.Format("{{id: \"{0}\", parent: \"{1}\", level: \"{2}\", Name: \"{3}\", Passed: \"{4}\", Failed: \"{5}\", Ignored: \"{6}\", Percent: \"{7}\", Progress: \"{8}\", Time: \"{9}\", Message: \"{10}\", StackTrace: \"{11}\", LineNo: \"{12}\", isLeaf: {13}, expanded: {14}, loaded: {15}}},", counter, classParent, "2", _method.Name, _passed, _failed, _ignored, string.Format("{0:00.00}", percentPass), strPercent, TimeSpan.Parse(_method.Duration).TotalMilliseconds, strError, strStack, strLine, "true", "false", "true");
sb.Append(strMethod);
}
}
classChartDataValue = "var classDataValue = [" + classChartDataValue + "];";
classChartDataText = "var classDataText = [" + classChartDataText + "];";
methoChartDataValue = "var methoDataValue = [" + methoChartDataValue + "];";
methoChartDataText = "var methoDataText = [" + methoChartDataText + "];";
methoChartDataColor = "var methoDataColor = [" + methoChartDataColor + "];";
}
sb.Append("],");
sb.Append("getColumnIndexByName = function (grid, columnName) {");
sb.Append("var cm = grid.jqGrid('getGridParam', 'colModel');");
sb.Append("for (var i = 0; i < cm.length; i += 1) {");
sb.Append("if (cm[i].name === columnName) {");
sb.Append("return i;");
sb.Append("}");
sb.Append("}");
sb.Append("return -1;");
sb.Append("},");
sb.Append("grid = $('#treegrid');");
sb.Append("grid.jqGrid({");
sb.Append("datatype: 'jsonstring',");
sb.Append("datastr: mydata,");
sb.Append("colNames: ['Id', 'Name', 'Passed', 'Failed', 'Ignored', '%', '', 'Time', 'Message','StackTrace','LineNo'],");
sb.Append("colModel: [");
sb.Append("{ name: 'id', index: 'id', width: 1, hidden: true, key: true },");
sb.Append("{ name: 'Name', index: 'Name', width: 380 },");
sb.Append("{ name: 'Passed', index: 'Passed', width: 70, align: 'right', formatter: testCounterFormat },");
sb.Append("{ name: 'Failed', index: 'Failed', width: 70, align: 'right', formatter: testCounterFormat },");
sb.Append("{ name: 'Ignored', index: 'Ignored', width: 70, align: 'right', formatter: testCounterFormat },");
sb.Append("{ name: 'Percent', index: 'Percent', width: 50, align: 'right' },");
sb.Append("{ name: 'Progress', index: 'Progress', width: 200, align: 'right', formatter: progressFormat },");
sb.Append("{ name: 'Time', index: 'Time', width: 75, align: 'right'},");
sb.Append("{ name: 'Message', index: 'Message', hidden: true, width: 100, align: 'right'},");
sb.Append("{ name: 'StackTrace', index: 'StackTrace', hidden: true, width: 100, align: 'right'},");
sb.Append("{ name: 'LineNo', index: 'LineNo', width: 100, hidden: true, align: 'right'}],");
sb.Append("height: 'auto',");
sb.Append("gridview: true,");
sb.Append("rowNum: 10000,");
sb.Append("sortname: 'id',");
sb.Append("treeGrid: true,");
sb.Append("treeGridModel: 'adjacency',");
sb.Append("treedatatype: 'local',");
sb.Append("ExpandColumn: 'Name',");
sb.Append("ondblClickRow: function(id) {");
sb.Append("parent.innerLayout.open('south');");
sb.Append("setErrorInfo(id);");
sb.Append("},");
sb.Append("onSelectRow: function(id){");
sb.Append("setErrorInfo(id);");
sb.Append("},");
sb.Append("jsonReader: {");
sb.Append("repeatitems: false,");
sb.Append("root: function (obj) { return obj; },");
sb.Append("page: function (obj) { return 1; },");
sb.Append("total: function (obj) { return 1; },");
sb.Append("records: function (obj) { return obj.length; }");
sb.Append("}");
sb.Append("});");
sb.Append("function setErrorInfo(id) {");
sb.Append("var doc = $('#tblError', top.document);");
sb.Append("doc.find('#dvErrorMessage').text($('#treegrid').getRowData(id)['Message']);");
sb.Append("doc.find('#dvLineNumber').text($('#treegrid').getRowData(id)['LineNo']);");
sb.Append("doc.find('#dvStackTrace').text($('#treegrid').getRowData(id)['StackTrace']);");
sb.Append("}");
sb.Append("function progressFormat(cellvalue, options, rowObject) {");
sb.Append("var progress = cellvalue.split(',');");
sb.Append("var pass = Math.round(progress[0]) * 2;");
sb.Append("var fail = Math.round(progress[1]) * 2;");
sb.Append("var ignore = Math.round(progress[2]) * 2;");
sb.Append("var strProgress = \"<div class='ProgressWrapper'>");
sb.Append("<div class='ProgressPass' title='\"+ Number(progress[0]).toFixed(2) +\"% Passed' style='width: \" + pass + \"px'></div>");
sb.Append("<div class='ProgressFail' title='\"+ Number(progress[1]).toFixed(2) +\"% Failed' style='width: \" + fail + \"px'></div>");
sb.Append("<div class='ProgressIgnore' title='\"+ Number(progress[2]).toFixed(2) +\"% Ignored' style='width: \" + ignore + \"px'></div>");
sb.Append("</div>\";");
sb.Append("return strProgress;");
sb.Append("}");
sb.Append("function testCounterFormat(cellvalue, options, rowObject) {");
sb.Append("return cellvalue;");
sb.Append("}");
sb.Append("grid.jqGrid('setLabel', 'Passed', '', { 'text-align': 'right' });");
sb.Append("grid.jqGrid('setLabel', 'Failed', '', { 'text-align': 'right' });");
sb.Append("grid.jqGrid('setLabel', 'Ignored', '', { 'text-align': 'right' });");
sb.Append("grid.jqGrid('setLabel', 'Percent', '', { 'text-align': 'right' });");
sb.Append("});");
string xmlTestResultTable = sb.ToString().Replace("},],", "}],");
WriteFile("Table.js", xmlTestResultTable);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
}
private static void CreateTestResultChart()
{
StringBuilder sb = new StringBuilder();
sb.Append("var testResultStatus = ['Passed', 'Failed', 'Ignored'];");
sb.Append("var testResultColor = ['#ABD874', '#E18D87', '#F4AD7C'];");
sb.Append(projectChartDataValue);
sb.Append(classChartDataValue);
sb.Append(classChartDataText);
sb.Append(methoChartDataValue);
sb.Append(methoChartDataText);
sb.Append(methoChartDataColor);
string xmlTestResultTable = sb.ToString().Replace(",]", "]");
WriteFile("Chart.js", xmlTestResultTable);
}
private static void WriteFile(string FileName, string FileContent)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(Path.Combine(folderPath, FileName)))
{
file.WriteLine(FileContent);
}
}
This method will create dynamic batch (mstestrunner.bat) file with three parameters. Using these parameters it will call from this application to perform MS Test on test project container. After successfully completion of batch command then it will create new file (.trx) for getting statistics of your test project.
private static void GenerateTRXFile(string MsTestExePath, string TestContainerFilePath)
{
trxFilePath = Path.Combine(folderPath, FILENAME_TRX);
string commandText = "\"" + MsTestExePath + "\" /testcontainer:\"" + TestContainerFilePath + "\" /resultsfile:\"" + trxFilePath + "\"";
WriteFile("mstestrunner.bat", commandText);
ExecuteBatchFile();
}
new Process()
command.private static void ExecuteBatchFile()
{
Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.FileName = Path.Combine(folderPath, "mstestrunner.bat");
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
private static bool RecognizeParameters(string[] args)
{
if (args.Length >= 4 && args.Length <= 10)
{
int i = 0;
while (i < args.Length)
{
switch (args[i].ToLower())
{
case "/m":
case "/mstestexepath":
case "-m":
case "-mstestexepath":
if (args.Length > i)
{
MSTestExePathParam = args[i + 1];
i += 2;
}
else
return false;
break;
case "/tc":
case "/testcontainerfolderpath":
case "-tc":
case "-testcontainerfolderpath":
if (args.Length > i)
{
TestContainerFolderPathParam = args[i + 1];
i += 2;
}
else
return false;
break;
case "/t":
case "/trxfilepath":
case "-t":
case "-trxfilepath":
if (args.Length > i)
{
trxFilePath = args[i + 1];
i += 2;
}
else
return false;
break;
case "/d":
case "/destinationfolderpath":
case "-d":
case "-destinationfolderpath":
if (args.Length > i)
{
DestinationFolderParam = args[i + 1];
i += 2;
}
else
return false;
break;
case "/?":
case "/help":
case "-?":
case "-help":
return false;
default:
Console.WriteLine("Error: Unrecognized parameter\n");
return false;
}
}
return true;
}
return false;
}
MSTestResultViewer.Consol.exe /?h
Code:private static void DisplayCommandLineHelp()
{
StringBuilder sb = new StringBuilder();
sb.Append(string.Format("{0}.exe\n", Title));
sb.Append(string.Format("[</M MSTestExePath>\n"));
sb.Append(string.Format(" </TC TestContainerFolderPath>] :optional if you set /T TRXFilePath\n"));
sb.Append(string.Format("[</T TRXFilePath>]\n"));
sb.Append(string.Format("</D DestinationFolder> :not available\n"));
sb.Append(string.Format("</L LogFile> :not available\n"));
sb.Append(string.Format("</H HelpFile> :not available\n"));
sb.Append(string.Format("</? Help>\n"));
Console.Write(sb.ToString());
Console.ReadKey();
}
private static bool CopyFilesWithSubFolders(string SourcePath, string DestinationPath, bool overwriteexisting, string Pattern = "*.*")
{
bool ret = true;
try
{
SourcePath = SourcePath.EndsWith(@"\") ? SourcePath : SourcePath + @"\";
DestinationPath = DestinationPath.EndsWith(@"\") ? DestinationPath : DestinationPath + @"\";
if (Directory.Exists(SourcePath))
{
if (Directory.Exists(DestinationPath) == false) Directory.CreateDirectory(DestinationPath);
foreach (string fls in Directory.GetFiles(SourcePath, Pattern))
{
FileInfo flinfo = new FileInfo(fls);
flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
}
foreach (string drs in Directory.GetDirectories(SourcePath))
{
DirectoryInfo drinfo = new DirectoryInfo(drs);
if (CopyFilesWithSubFolders(drs, DestinationPath + drinfo.Name, overwriteexisting, Pattern) == false) ret = false;
}
}
else
{
ret = false;
}
}
catch (Exception ex)
{
ret = false;
}
return ret;
}
- MsTestResultViewer a is free, and I hope that you will find it is useful. If you’d like to support future development and new product features, please make a your valuable comments, feedback, suggestions or appreciation via Comments, mail, messages, likes or share.
These efforts are used to cover and improve product efficiency within timeframe.
- Third-Party Notice and License Information
- RGraph (http://www.rgraph.net) RGraph is free to use on non-commercial websites such as personal blogs, educational or charity sites - you don't need to buy a license - just link to the RGraph website on your own site. The full source is included in the download and you can edit it as you need.
- jQuery UI Layout Plug-in (http://layout.jquery-dev.net) plug-in was inspired by the extJS border-layout, and recreates that functionality as a jQuery plug-in. The UI Layout plug-in can create any UI look you want - from simple headers or sidebars, to a complex application with toolbars, menus, help-panels, status bars, sub-forms, etc.
- jQuery Grid Plugin – jqGrid (http://www.trirand.net/licensing.aspx) is and will always be licensed under the most permissive and free MIT license. However, many customers and organizations require commercial grade licenses, support and features.
- License Open-source licenses are also commonly free, allowing for modification, redistribution, and commercial use without having to pay to the original author. This is open source software and from here Web App Development Company Blog you will get updated setup, source code and complete usage guideline document for MsTestResultViewer.