I have the below program
class Program
{
static void Main(string[] args)
{
List<Assembly> failedAssemblies = LoadAssembly();
string batchFile = "D:\1円" + ".bat";
FileStream fs = File.Create(batchFile);
fs.Close();
using (StreamWriter outFile = new StreamWriter(batchFile))
{
string command = @"echo off";
outFile.WriteLine(command);
Process(outFile, failedAssemblies);
}
}
private static void Process(StreamWriter outFile, List<Assembly> assembliesList)
{
string command = "mstest.exe ";
string testcontainer = " /testcontainer:";
List<string> testContainerAssemblies = new List<string>(4);
outFile.WriteLine("SET Path=%MsTestPath%");
foreach (Assembly assmbly in assembliesList)
{
command = string.Empty;
if (!testContainerAssemblies.Contains(assmbly.AssemblyName))
{
outFile.WriteLine(' ');
testContainerAssemblies.Add(assmbly.AssemblyName);
command = "mstest.exe ";
command += testcontainer + "\\" + assmbly.AssemblyName + " ";
command += "/resultsfile:\"" + "\\Resultfile_" + assmbly.AssemblyName.Replace(".dll", "") + "_" + "1".ToString() + ".trx\"";
command += " /runconfig:";
command += " /detail:owner";
command += " /detail:duration";
command += " /detail:description";
command += " /unique ";
}
command += " /test:" + assmbly.NameSpaceName + "." + assmbly.ClassName + "." + assmbly.FunctionName;
outFile.Write(command);
}
}
private static List<Assembly> LoadAssembly()
{
var assemblyCollection = new List<Assembly>();
assemblyCollection.Add(new Assembly { AssemblyName = "AccountTestBase.dll", NameSpaceName = "ECardTest", ClassName = "ECardTest", FunctionName = "ECardTestDownLoadPKGSuccess" });
assemblyCollection.Add(new Assembly { AssemblyName = "AccountTestBase.dll", NameSpaceName = "AccountTest", ClassName = "IAccountTest", FunctionName = "Somefunc" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "BoletoFunctionalTestCase" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "BoletoEndToEndFunctionalTestCase" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "BoletoPurcahseTestCase" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "CreditCard_ResumeOrder_Success" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "CreditCard_EURCurr_USBilling_ENUS" });
assemblyCollection.Add(new Assembly { AssemblyName = "TestPayment.dll", NameSpaceName = "TestPayment", ClassName = "CreditCardTestCases", FunctionName = "DinersClubPayment" });
return assemblyCollection;
}
}
public class Assembly
{
public string AssemblyName { get; set; }
public string ClassName { get; set; }
public string FunctionName { get; set; }
public string NameSpaceName { get; set; }
}
It generates the below output
echo off
SET Path=%MsTestPath%
mstest.exe /testcontainer:\AccountTestBase.dll /resultsfile:"\Resultfile_AccountTestBase_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique /test:ECardTest.ECardTest.ECardTestDownLoadPKGSuccess /test:AccountTest.IAccountTest.Somefunc
mstest.exe /testcontainer:\TestPayment.dll /resultsfile:"\Resultfile_TestPayment_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique /test:TestPayment.CreditCardTestCases.BoletoFunctionalTestCase /test:TestPayment.CreditCardTestCases.BoletoEndToEndFunctionalTestCase /test:TestPayment.CreditCardTestCases.BoletoPurcahseTestCase /test:TestPayment.CreditCardTestCases.CreditCard_ResumeOrder_Success /test:TestPayment.CreditCardTestCases.CreditCard_EURCurr_USBilling_ENUS /test:TestPayment.CreditCardTestCases.DinersClubPayment
Now a new requirement has come where we need to break the output based on the limits passed.
Say If the Limit is 300, the output will be
echo off
SET Path=%MsTestPath%
mstest.exe /testcontainer:\AccountTestBase.dll /resultsfile:"\Resultfile_AccountTestBase_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique /test:ECardTest.ECardTest.ECardTestDownLoadPKGSuccess
mstest.exe /testcontainer:\TestPayment.dll /resultsfile:"\Resultfile_TestPayment_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique /test:TestPayment.CreditCardTestCases.BoletoFunctionalTestCase /test:TestPayment.CreditCardTestCases.BoletoEndToEndFunctionalTestCase
mstest.exe /testcontainer:\TestPayment.dll /resultsfile:"\Resultfile_TestPayment_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique /test:TestPayment.CreditCardTestCases.BoletoPurcahseTestCase /test:TestPayment.CreditCardTestCases.CreditCard_ResumeOrder_Success /test:TestPayment.CreditCardTestCases.CreditCard_EURCurr_USBilling_ENUS /test:TestPayment.CreditCardTestCases.DinersClubPayment
i.e. the firstone has a total character limit of 210(approx) and henceforth it remain the same.
The second one has crossed the limit and needs to be split into two parts. The first one is split over two lines (290) because adding one more command to it will cross the limit. That's why we need to split it into two parts.
One more point is that, it cannot just split precisely based on the Limit value provided. Because it is a MSTest command that needs to be run. Henceforth,
`"mstest.exe /testcontainer:\TestPayment.dll /resultsfile:"\Resultfile_TestPayment_1.trx" /runconfig: /detail:owner /detail:duration /detail:description /unique"` will always come and then `"test/..."`
I have acheived the the final output but needs a better one(i am sure it can be)
private static void Process(StreamWriter outFile, List<Assembly> failedAssemblies)
{
int MAXLIMIT = 2000;
string command = "mstest.exe ";
string testcontainer = " /testcontainer:";
List<string> testContainerAssemblies = new List<string>(4);
int sum = 0;
outFile.WriteLine("SET Path=%MsTestPath%");
var failedAssemblyCollections = (from x in failedAssemblies
group x by x.AssemblyName into g
select new
{
AssemblyNames = g.Key,
FullyQualifiedTestMethods = g.Select(i => " /test:" + i.NameSpaceName + "." + i.ClassName + "." + i.FunctionName),
FullyQualifiedTestMethodsLen = g.Select(i => Convert.ToString(" /test:" + i.NameSpaceName + "." + i.ClassName + "." + i.FunctionName).Length)
});
foreach (var item in failedAssemblyCollections)
{
var assemblyNames = item.AssemblyNames;
var methodsLengths = item.FullyQualifiedTestMethodsLen.ToList();
var flag = true;
int counter = 0;
//write for the very first time
if (flag)
{
Write(outFile, ref command, testcontainer, assemblyNames);
flag = false;
}
for (int i = 0; i < methodsLengths.Count; i++)
{
sum += methodsLengths[i];
if (sum <= MAXLIMIT)
{
command += item.FullyQualifiedTestMethods.ToList()[i];
//this will execute when a long command is splitted and is written in new trx files
if (flag)
{
counter++;
Write(outFile, ref command, testcontainer, assemblyNames);
flag = false;
}
}
//if the value crosses max limit
//write the current output
//then reset variables to original
if (sum >= MAXLIMIT)
{
outFile.Write(command);
sum = 0;
flag = true;
i--;
}
}
outFile.Write(command);
}
}
private static void Write(StreamWriter outFile, ref string command, string testcontainer, string assemblyNames)
{
outFile.WriteLine(' ');
command = "mstest.exe ";
command += testcontainer + "\\" + assemblyNames + " ";
command += " /runconfig:";
command += " /detail:owner";
command += " /detail:duration";
command += " /detail:description";
command += " /unique ";
}
Thanks in advance
1 Answer 1
First off, you are right, this is much more complicated than it needs to be. I do like most of the naming conventions, casing and white space in your code.
I would start off by making maxLimit
, command
, and testContainer
class level constants.
The dynamic object you create while making the failedAssemblyCollections
doesn't need the FullyQualifiedTestMethodsLen. This can be calculated by getting the length of FullyQualifiedTestMethods in the code.
Instead of so many outFile.WriteLines, I would format the strings for each line and write when appropriate. This would eliminate the need for flag
and sum
, which is a good thing, because these are not well named or used variables,.
I'm not sure what counter
does, it is only ever assigned. Get rid of it.
Basically, I've found your code to be overly complex, it took me a 2 hours to figure it out.
The good news is, I think I've simplified it. I'm not going to go through line by line, I hope the code is self explanatory. You might want to pull the processing out into its own class, I just included it in the program class. I've also excluded some of your original code which I think did not need cleaning up.
class Program
{
private const int Maxlimit = 300;
private const string Testcontainer = "/testcontainer:";
private const string Command = "mstest.exe";
private const string EchoOff = @"echo off";
private const string BatchFile = "D:\1円" + ".bat";
private const string SetPath = "SET Path=%MsTestPath%";
static void Main()
{
var failedAssemblies = LoadAssembly();
var fs = File.Create(BatchFile);
fs.Close();
using (var outFile = new StreamWriter(BatchFile))
{
outFile.WriteLine(EchoOff);
Process(outFile, failedAssemblies);
}
}
private static void Process(TextWriter outFile, IEnumerable<Assembly> failedAssemblies)
{
outFile.WriteLine(SetPath);
var failedAssemblyCollections = (from x in failedAssemblies
group x by x.AssemblyName into g
select new
{
AssemblyName = g.Key,
FullyQualifiedTestMethods = g.Select(i => " /test:" + i.NameSpaceName + "." + i.ClassName + "." + i.FunctionName)
});
foreach (var item in failedAssemblyCollections)
{
var commandLine = InitializeLine(item.AssemblyName);
foreach(var method in item.FullyQualifiedTestMethods)
{
if (commandLine.Length + method.Length > Maxlimit)
{
outFile.WriteLine(commandLine.ToString());
commandLine = InitializeLine(item.AssemblyName);
}
commandLine.Append(" ");
commandLine.Append(method);
}
outFile.WriteLine(commandLine.ToString());
}
}
private static StringBuilder InitializeLine(string assemblyName)
{
var commandLine = new StringBuilder(Command);
commandLine.Append(Write(assemblyName));
return commandLine;
}
private static string Write(string assemblyName)
{
var command = " ";
command += Testcontainer + "\\" + assemblyName;
command += " /runconfig:";
command += " /detail:owner";
command += " /detail:duration";
command += " /detail:description";
command += " /unique";
return command;
}
}