2
\$\begingroup\$

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

Jeff Vanzella
4,3182 gold badges24 silver badges33 bronze badges
asked Apr 2, 2013 at 1:59
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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;
 }
}
answered Apr 2, 2013 at 5:27
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.