如何测试 DataRows 中的所有参数组合
How do test all combinations of parameters in DataRows
假设我有这样的测试方法:
[TestMethod]
[DataRow( 0, 0, 0 )]
[DataRow( 0, 0, 1 )]
[DataRow( 0, 1, 0 )]
[DataRow( 0, 1, 1 )]
[DataRow( 1, 0, 0 )]
[DataRow( 1, 0, 1 )]
[DataRow( 1, 1, 0 )]
[DataRow( 1, 1, 1 )]
public void ReallyCoolTest( int a, int b, int c )
{
// some really cool test code that uses a, b, and c
}
此测试针对等于 0 或 1 的 a、b 和 c 的所有组合。三个参数中只有两个值,需要 8 DataRow
行!
我真正喜欢做的是这样的事情:
[TestMethod]
[DataMatrix( {0,1}, {0,1}, {0,1} )]
public void ReallyCoolTest( int a, int b, int c )
{
// some really cool test code that uses a, b, and c
}
我想为每个参数指定一些值并测试所有组合。使用 MS 测试有类似的东西吗?
注意:我知道 DataSource
属性。但是,我希望值在代码中而不是在外部文件中。
您还可以在运行时使用 DynamicData attribute 生成测试参数。您可以给方法的名称 returns 一个 IEnumerable of object[]。这些用作测试的参数。
[DataTestMethod]
[DynamicData(nameof(GetData), DynamicDataSourceType.Method)]
public void ReallyCoolTest(int a, int b, int expected)
{
// ...
}
public static IEnumerable<object[]> GetData()
{
for(int i = 0; i <= 1; i++)
{
for(int j = 0; j <= 1; j++)
{
for(int k = 0; k <=1; k++)
{
yield return new object[] {i,j,k};
}
}
}
}
我能想到的最好的是:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace UnitTestProject
{
[TestClass]
public class TestThing
{
[CombinatorialTestMethod]
[DataRow( 0 , 9 )]
[DataRow( 1 , 2 )]
[DataRow( 3 , 4 , 5 , 7)]
public void TestMe( int a , int b , int c )
{
if ( b * 2 == c )
throw new Exception( "blah!" );
}
}
public class CombinatorialTestMethodAttribute : TestMethodAttribute
{
private object[][] argsArrays = new object[][] { };
private List<object[]> argumentsList = new( );
public override TestResult[] Execute( ITestMethod testMethod )
{
// Get arrays of arguments, then construct arguments list
List<object[]> argsArraysList = new( );
foreach ( DataRowAttribute parameters in testMethod.GetAttributes<DataRowAttribute>( false ) )
{
argsArraysList.Add( parameters.Data );
}
this.argsArrays = argsArraysList.ToArray( );
this.ConstructArgumentsList( );
// Invoke the test
List<TestResult> results = new( );
foreach ( object[] args in this.argumentsList )
{
try
{
TestResult result = testMethod.Invoke( args );
results.Add( result );
}
catch ( Exception e )
{
results.Add( new TestResult( )
{
Outcome = UnitTestOutcome.Failed ,
TestFailureException = e ,
} );
}
}
return results.ToArray( );
}
private void ConstructArgumentsList( )
{
int num_params = this.argsArrays.Length;
int[] indices = new int[num_params];
bool done = num_params == 0;
while ( !done )
{
// Get next arguemnt combination
object[] args = new object[num_params];
for ( int i = 0 ; i < num_params ; i += 1 )
{
args[i] = this.argsArrays[i][indices[i]];
}
this.argumentsList.Add( args );
// increment indices
for ( int i = num_params - 1 ; i >= 0 ; i -= 1 )
{
indices[i] += 1;
if ( indices[i] >= this.argsArrays[i].Length )
{
indices[i] = 0;
if ( i == 0 )
{
done = true;
break;
}
}
else
{
break;
}
}
}
}
}
}
我不会使用它,因为我对它还不是 100% 满意,但我可能会 fiddle 更多并稍后发布一些东西。
假设我有这样的测试方法:
[TestMethod]
[DataRow( 0, 0, 0 )]
[DataRow( 0, 0, 1 )]
[DataRow( 0, 1, 0 )]
[DataRow( 0, 1, 1 )]
[DataRow( 1, 0, 0 )]
[DataRow( 1, 0, 1 )]
[DataRow( 1, 1, 0 )]
[DataRow( 1, 1, 1 )]
public void ReallyCoolTest( int a, int b, int c )
{
// some really cool test code that uses a, b, and c
}
此测试针对等于 0 或 1 的 a、b 和 c 的所有组合。三个参数中只有两个值,需要 8 DataRow
行!
我真正喜欢做的是这样的事情:
[TestMethod]
[DataMatrix( {0,1}, {0,1}, {0,1} )]
public void ReallyCoolTest( int a, int b, int c )
{
// some really cool test code that uses a, b, and c
}
我想为每个参数指定一些值并测试所有组合。使用 MS 测试有类似的东西吗?
注意:我知道 DataSource
属性。但是,我希望值在代码中而不是在外部文件中。
您还可以在运行时使用 DynamicData attribute 生成测试参数。您可以给方法的名称 returns 一个 IEnumerable of object[]。这些用作测试的参数。
[DataTestMethod]
[DynamicData(nameof(GetData), DynamicDataSourceType.Method)]
public void ReallyCoolTest(int a, int b, int expected)
{
// ...
}
public static IEnumerable<object[]> GetData()
{
for(int i = 0; i <= 1; i++)
{
for(int j = 0; j <= 1; j++)
{
for(int k = 0; k <=1; k++)
{
yield return new object[] {i,j,k};
}
}
}
}
我能想到的最好的是:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace UnitTestProject
{
[TestClass]
public class TestThing
{
[CombinatorialTestMethod]
[DataRow( 0 , 9 )]
[DataRow( 1 , 2 )]
[DataRow( 3 , 4 , 5 , 7)]
public void TestMe( int a , int b , int c )
{
if ( b * 2 == c )
throw new Exception( "blah!" );
}
}
public class CombinatorialTestMethodAttribute : TestMethodAttribute
{
private object[][] argsArrays = new object[][] { };
private List<object[]> argumentsList = new( );
public override TestResult[] Execute( ITestMethod testMethod )
{
// Get arrays of arguments, then construct arguments list
List<object[]> argsArraysList = new( );
foreach ( DataRowAttribute parameters in testMethod.GetAttributes<DataRowAttribute>( false ) )
{
argsArraysList.Add( parameters.Data );
}
this.argsArrays = argsArraysList.ToArray( );
this.ConstructArgumentsList( );
// Invoke the test
List<TestResult> results = new( );
foreach ( object[] args in this.argumentsList )
{
try
{
TestResult result = testMethod.Invoke( args );
results.Add( result );
}
catch ( Exception e )
{
results.Add( new TestResult( )
{
Outcome = UnitTestOutcome.Failed ,
TestFailureException = e ,
} );
}
}
return results.ToArray( );
}
private void ConstructArgumentsList( )
{
int num_params = this.argsArrays.Length;
int[] indices = new int[num_params];
bool done = num_params == 0;
while ( !done )
{
// Get next arguemnt combination
object[] args = new object[num_params];
for ( int i = 0 ; i < num_params ; i += 1 )
{
args[i] = this.argsArrays[i][indices[i]];
}
this.argumentsList.Add( args );
// increment indices
for ( int i = num_params - 1 ; i >= 0 ; i -= 1 )
{
indices[i] += 1;
if ( indices[i] >= this.argsArrays[i].Length )
{
indices[i] = 0;
if ( i == 0 )
{
done = true;
break;
}
}
else
{
break;
}
}
}
}
}
}
我不会使用它,因为我对它还不是 100% 满意,但我可能会 fiddle 更多并稍后发布一些东西。