Я не нашел никакого решения, поэтому я реализую небольшое решение, которое работает хорошо, но не обрабатывает следующие случаи:
- Not Calling the TestCleanup
- Not Callsing Очистка сборки
- Не обрабатывается, когда тест
async Task
- Не обрабатывает атрибут
DataRow
Но для первоначального решения все в порядке. Вот код этого:
/// <summary>
/// This class is able to run a test function from a test assembly.
/// This is used for automated test possibilities. This class is not for production code.
/// The <see cref="ExecuteTest"/> can be ca;lled many times you want, the initizalization will be done automatically
/// The class not handle all Ms Test feature, just the following:
/// - <see cref="AssemblyInitializeAttribute"/>
/// </summary>
public class TestFunctionRunner
{
/// <summary>
/// The path of the dll file, which is contains the test function
/// </summary>
public string AssemblyPath { get; }
/// <summary>
/// The instance of the the test assembly
/// </summary>
public Assembly TestAssembly { get; private set; }
/// <summary>
/// Name of the test class, which contains the the test function
/// </summary>
public string TestClassName { get; }
/// <summary>
/// The <see cref="Type"/> of the test class
/// </summary>
public Type TestClassType { get; private set; }
/// <summary>
/// The created instance of the TestClass
/// </summary>
public object TestClassInstance { get; private set; }
/// <summary>
/// Name of the test function which will be executed each time
/// </summary>
public string TestFunctionName { get; }
private bool IsAssemblyInitialized = false;
/// <summary>
/// Construct a test runner class, to execute a test function from code.
/// </summary>
/// <param name="assemblyPath">The path of the dll file, which is contains the test function </param>
/// <param name="testClass">Name of the test class, which contains the the test function</param>
/// <param name="testFunction"> Name of the test function which will be executed each time</param>
public TestFunctionRunner( string assemblyPath, string testClass, string testFunction )
{
AssemblyPath = assemblyPath;
TestClassName = testClass;
TestFunctionName = testFunction;
InitializeRunner();
}
private void InitializeRunner()
{
TestAssembly = Assembly.LoadFrom( AssemblyPath );
TestClassType = TestAssembly.DefinedTypes.FirstOrDefault( t => t.Name == TestClassName );
if( TestClassType == null )
throw new Exception( $"The class name: {TestClassName} not found in assembly {TestAssembly.FullName}" );
TestClassInstance = Activator.CreateInstance( TestClassType );
}
/// <summary>
/// Execute test given test
/// </summary>
public void ExecuteTest()
{
string workingDirectory = Directory.GetCurrentDirectory();
if( string.IsNullOrEmpty( Path.GetDirectoryName( AssemblyPath ) ) == false )
Directory.SetCurrentDirectory( Path.GetDirectoryName( AssemblyPath ) );
if( IsAssemblyInitialized == false )
InitializeAssembly();
ExecuteTestInitialize();
TestClassType.InvokeMember( name: TestFunctionName
, invokeAttr: BindingFlags.Default | BindingFlags.InvokeMethod
, binder: null
, target: TestClassInstance
, args: null );
Directory.SetCurrentDirectory( workingDirectory );
}
private void InitializeAssembly()
{
IEnumerable<TypeInfo> testClasses = TestAssembly
.DefinedTypes
.Where( t => t.GetCustomAttribute<TestClassAttribute>() != null );
MethodInfo assemblyInitializeMethod = null;
foreach( TypeInfo testClass in testClasses )
{
assemblyInitializeMethod = testClass.GetMethods().FirstOrDefault( mi => mi.GetCustomAttribute<AssemblyInitializeAttribute>() != null );
if( assemblyInitializeMethod != null )
break;
}
if( assemblyInitializeMethod != null )
{
if( assemblyInitializeMethod.IsStatic == false )
throw new Exception( $"Test initialize error: assembly initialize method : {assemblyInitializeMethod.Name} must be static " );
if( assemblyInitializeMethod.GetParameters().Count() != 1 )
throw new Exception( $"Test initialize error: assembly initialize method : {assemblyInitializeMethod.Name} must have one paramet, whe type is : {typeof(TestContext)}" );
assemblyInitializeMethod.Invoke( null, new object[] { new MyTestContext() } );
}
MethodInfo classInitializeMethod = TestClassType
.GetMethods()
.FirstOrDefault( m => m.GetCustomAttribute<ClassInitializeAttribute>() != null );
if( classInitializeMethod != null )
{
if( classInitializeMethod.GetParameters().Count() > 0 )
throw new Exception( $"Test initialize error: class initialize method : {classInitializeMethod.Name} must be parameterless " );
classInitializeMethod.Invoke( TestClassInstance, null );
}
IsAssemblyInitialized = true;
}
private void ExecuteTestInitialize()
{
MethodInfo testInitializeMethod = TestClassType
.GetMethods()
.FirstOrDefault( m => m.GetCustomAttribute<TestInitializeAttribute>() != null );
if( testInitializeMethod.GetParameters().Count() > 0 )
throw new Exception( $"Test initialize error: test initialize method : {testInitializeMethod.Name} must be parameterless" );
testInitializeMethod.Invoke( TestClassInstance, null );
}
private class MyTestContext : TestContext
{
public override IDictionary Properties => throw new NotImplementedException();
public override void AddResultFile( string fileName )
{
}
public override void WriteLine( string message )
{
Console.WriteLine( message );
Debug.WriteLine( message );
}
public override void WriteLine( string format, params object[] args )
{
Console.WriteLine( format, args );
Debug.WriteLine( format, args );
}
}
}