Last active
December 31, 2015 06:19
-
-
Save dlwiii/7946777 to your computer and use it in GitHub Desktop.
Test Harness wrapper. I use this all the time to give a console application the generic ability to run specific methods in specific classes with or without arguments. It turns my console app into a Swiss army knife!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Dimension.Connectors.Procore.Test | |
{ | |
public class TestMain | |
{ | |
private static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | |
public static void Main(string[] args) | |
{ | |
var tester = new TestMain(); | |
tester.RunDiagnostic(args); | |
} | |
public int RunDiagnostic(string[] args) | |
{ | |
DateTime start = DateTime.Now; | |
int i = 0; | |
try | |
{ | |
log.Info("\n\n\t***Starting Test"); | |
string allArgs = ""; | |
foreach (string arg in args) | |
{ | |
allArgs += arg + " "; | |
} | |
allArgs = allArgs.Trim(); | |
log.Info("Args: " + allArgs); | |
i = RunTest(args); | |
} | |
catch (Exception ex) | |
{ | |
log.Error("Error: " + ex.ToString()); | |
log.Error("Stack: " + ex.StackTrace.ToString()); | |
if (ex.InnerException != null) | |
{ | |
// an exception from an invoked method | |
log.Error("Inner Error: " + ex.InnerException.ToString()); | |
log.Error("Inner Stack: " + ex.InnerException.StackTrace.ToString()); | |
} | |
} | |
log.Info("RunTime: " + ((TimeSpan)(DateTime.Now - start)).TotalSeconds.ToString()); | |
log.Info("Result: " + i.ToString()); | |
return i; | |
} | |
int RunTest(string[] args) | |
{ | |
if (args.Length < 2) | |
{ | |
Help(); | |
return 1; | |
} | |
// get a list of all classes that have the attribute "TestClass" | |
string classToRun = args[0]; | |
string methodToRun = args[1]; | |
string[] subargs = null; | |
if (args.Length > 2) | |
{ | |
subargs = new string[args.Length - 2]; | |
for (int n = 2; n < args.Length; n++) | |
{ | |
subargs[n - 2] = args[n]; | |
} | |
} | |
var allDiagnostics = GetClassesAndMethods(); | |
var matches = allDiagnostics.Where(c => c.TheClass.Name == classToRun && c.TheMethod.Name == methodToRun).ToList(); | |
if (matches.Count() == 1) | |
{ | |
var match = matches[0]; | |
Invoke(match.TheClass, match.TheMethod, subargs); | |
} | |
else if (matches.Count() > 1) | |
{ | |
log.Warn("There is more than one match to this class and method - harass the developer!"); | |
return 1; | |
} | |
else | |
{ | |
log.WarnFormat("Requested class [{0}] and method [{1}] not found", classToRun, methodToRun); | |
Help(); | |
return 1; | |
} | |
return 0; | |
} | |
protected void Help() | |
{ | |
var allDiagnostics = GetClassesAndMethods(); | |
// todo: follow some nice standard, winging it for now | |
log.Error("\nusage: CLASS METHOD <arguments...>"); | |
var lastClassName = ""; | |
foreach (var cm in allDiagnostics) | |
{ | |
if (lastClassName != cm.TheClass.Name) | |
{ | |
log.Info("\nClass: " + cm.TheClass.Name); | |
lastClassName = cm.TheClass.Name; | |
} | |
string message = ""; | |
foreach (ParameterInfo pi in cm.TheMethod.GetParameters()) | |
{ | |
message += " " + pi.Name; | |
} | |
log.Info("\tMethod: " + cm.TheMethod.Name + message); | |
} | |
} | |
public class ClassAndMethod | |
{ | |
public Type TheClass; | |
public MethodInfo TheMethod; | |
} | |
public IList<ClassAndMethod> GetClassesAndMethods() | |
{ | |
var result = new List<ClassAndMethod>(); | |
Assembly[] asses = AppDomain.CurrentDomain.GetAssemblies(); | |
Assembly theAss = Assembly.GetEntryAssembly(); | |
Type[] types = null; | |
try | |
{ | |
types = theAss.GetTypes(); | |
} | |
catch (ReflectionTypeLoadException ex) | |
{ | |
foreach (Exception le in ex.LoaderExceptions) | |
{ | |
log.Error(le.Message); | |
} | |
} | |
foreach (Type typ in types) | |
{ | |
// we want this one | |
Object[] testClasses = typ.GetCustomAttributes(typeof(TestClassAttribute), false); | |
if (testClasses.Length > 0) | |
{ | |
foreach (MethodInfo mi in typ.GetMethods()) | |
{ | |
Object[] testMethods = mi.GetCustomAttributes(typeof(TestMethodAttribute), false); | |
if (testMethods.Length > 0) | |
{ | |
result.Add( new ClassAndMethod{TheClass=typ, TheMethod = mi}); | |
} | |
} | |
} | |
} | |
return result; | |
} | |
protected void Invoke(Type testClass, MemberInfo method, string[] args) | |
{ | |
// invoke this static, void method | |
DateTime start = DateTime.Now; | |
object result; | |
object baseObject = Activator.CreateInstance(testClass); | |
result = testClass.InvokeMember(method.Name, BindingFlags.Default | BindingFlags.InvokeMethod | |
, null, baseObject, args); | |
log.Info("RunTime: " + ((TimeSpan)(DateTime.Now - start)).TotalSeconds.ToString()); | |
return; | |
} | |
} | |
public class TestClassAttribute : Attribute | |
{ | |
} | |
public class TestMethodAttribute : Attribute | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment