In NUnit there is a SimpleTestRunner
class to execute one simple test. Here is the doc for it: GitHub Code
Is there a similar class or functionality when I use MS Test Framework?
There is a simple way, to load assembly with Assembly.LoadFrom
and after just search the type and the Invoke a test function. But this mechanism does not handle the [AssemblyInitialize]
, the [TestInitialize]
and [DataRow]
features all others. And does not handle the way correctly when the test is async
.
So The question, is there any possibility to run an Ms Test Test function from code? Any Opensource or official solution is welcome:)
I did not found any solution, So I implement a little solution, which works well, but does not handle the following cases:
async Task
DataRow
attributeBut for initial solution is OK. Here is the code of it:
/// <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 );
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.