wasnt nate

Simple Tool to Run Visual Studio Unit Tests without MsTest

Here is a simple tool to run Visual Studio Unit Tests outside of mstest.

First the program outputs some basic banner information

static void Main(string[] args)
{
  Console.WriteLine("N8test - {0}", 
        Assembly.GetExecutingAssembly().GetName().Version);
  Console.WriteLine("Implementation by Nate Bachmeier");
  Console.WriteLine("//wasntnate.com");

  Console.WriteLine("Running tests..");

Next it will load any assemblies that have been specified as arguments.

Note that this requires the full path; with using some additional calls to File, Directory, and Path this could easily work with relative paths.

var asmList = new List<Assembly>();
foreach (var arg in args)
{
  try
  {
    var file = new FileInfo(arg);
    if (file.Exists)
      asmList.Add(Assembly.LoadFile(file.FullName));
  }
  catch
  {
    UseColor(ConsoleColor.Red, () =>
      Console.WriteLine("Unable to open {0}", arg));
    continue;
  }
}

Find any public class that is tagged with [TestClass]

foreach (var testClass in 
   from asm in asmList
   from t in asm.GetExportedTypes()
   let atts = t.GetCustomAttributes(true)
   where (from a in atts
     where string.Equals(a.GetType().Name, "TestClassAttribute")
     select a).FirstOrDefault() != null
   select t)
{

Initialize our test class

   Console.WriteLine("================");
   Console.WriteLine(testClass.Name);
   Console.WriteLine("================");

    object instance;
    try
    {
      instance = Activator.CreateInstance(testClass);
    }
    catch (TargetInvocationException tie)
    {
      Console.WriteLine("Failed to initalize {0} due to {1}",
              testClass.Name, tie.InnerException.Message);
      continue;
    }

Find each public method that is tagged with [TestMethod]

foreach (var method in 
    from m in testClass.GetMethods()
    let atts = m.GetCustomAttributes(true)
    where (from a in atts
      where string.Equals(a.GetType().Name, "TestMethodAttribute")
      select a).FirstOrDefault() != null
      select m)
{

Attempt to execute it and report the runtime on success

   try
   {
     var stopwatch = new Stopwatch();
     stopwatch.Start();
     method.Invoke(instance, new object[] { });
     stopwatch.Stop();
     UseColor(ConsoleColor.Green, () =>
        Console.WriteLine("[S] {0} in {1} milli seconds", 
        method.Name, stopwatch.ElapsedMilliseconds));
   }
   catch (TargetInvocationException tie)
   {
      UseColor(ConsoleColor.Red, () =>
        Console.WriteLine("[F] {1} due to {1}", 
        method.Name, tie.InnerException));
   }
 }
}

Ask the user to press a key before leaving; useful for ‘F5-run’ scenarios

  Console.WriteLine("Press any key to exit");
  Console.ReadKey();
}

Finally a helper method to give us coloring while displaying messages

static void UseColor(ConsoleColor color, Action code)
{
  var orgColor = Console.ForegroundColor;
  Console.ForegroundColor = color;
  try
  {
    code();
  }
  finally
  {
    Console.ForegroundColor = orgColor;    
  }
}

Leave a Reply