访问TestCaseSource中的NUnit测试名称

时间:2014-10-15 03:59:34

标签: c# unit-testing nunit

我有一系列测试,我想在一堆不同的测试中使用相同的测试用例数据。

例如:

[Test, TestCaseSource("TestData")] 
public void Test1(Foo foo)
{
    // test 1
}

[Test, TestCaseSource("TestData")] 
public void Test2(Foo foo)
{
    // test 2
}

private static IEnumerable TestData() 
{
   TestCaseData data; 

   data = new TestCaseData(new Foo("aaa"));
   yield return data; 

   data = new TestCaseData(new Foo("bbb"));
   yield return data; 
}

这会导致一系列测试报告如下:

Namespace.That.Is.Very.Long.TestClass.Test1(Namespace.That.Is.Very.Long.Foo)  
Namespace.That.Is.Very.Long.TestClass.Test1(Namespace.That.Is.Very.Long.Foo)  
Namespace.That.Is.Very.Long.TestClass.Test2(Namespace.That.Is.Very.Long.Foo)  
Namespace.That.Is.Very.Long.TestClass.Test2(Namespace.That.Is.Very.Long.Foo)  

......当你不知道'foo'失败时,这并没有多大意义..

如果as suggested in this SO question我将名称设置为:

   data = new TestCaseData(new Foo("aaa"));
   data.SetName("foo=aaa");
   yield return data; 

...然后我的所有测试看起来都像这样:

foo=aaa   
foo=bbb  
foo=aaa  
foo=bbb 

所以我想弄清楚如何获取当前的测试方法名称。看来,as described in this other SO question可以通过TestContext完成。

但是,当TestContext.Current.Test存在时,所有属性(如Name)在尝试访问它们时都会抛出NullReferenceException。

是否有其他方法可以实现在测试名称中提供更多有用信息的目标?

5 个答案:

答案 0 :(得分:25)

属性TestName在NUnit 3中支持字符串格式化。

以下是一个示例用法:

private static IEnumerable TestData()
{
    TestCaseData data;

    data = new TestCaseData(new Foo("aaa"))
                            .SetName("case 1 {m}");
    yield return data;

    data = new TestCaseData(new Foo("bbb"));
    yield return data;
}

将产生以下输出:

enter image description here

如您所见,第一个案例的测试名称包含自定义前缀+方法名称。

使用this link了解有关NUnit的字符串格式化功能的更多信息。

此行为NUnitTestCaseBuilder (line 83)TestNameGenerator方法.GetDisplayName()可以使用2个类。

答案 1 :(得分:1)

这不是一个完美的答案,但到目前为止我找到的最佳解决方案是我为TestData发射器创建了一个包装器,它作为TestCaseSource传入。

[Test, TestCaseSource("TestData_Test1")] 
public void Test1(Foo foo)
{
    // test 1
}

[Test, TestCaseSource("TestData_Test2")] 
public void Test2(Foo foo)
{
    // test 2
}


private static IEnumerable TestData_Test1() 
{
   return TestData_Base("Test1"); 
} 

private static IEnumerable TestData_Test2() 
{
   return TestData_Base("Test2"); 
} 

private static IEnumerable TestData_Base(string testName) 
{
   TestCaseData data; 

   data = new TestCaseData(new Foo("aaa"));
   data.SetName(string.Format("{0}(Foo=aaa)", testName)); 
   yield return data; 

   data = new TestCaseData(new Foo("bbb"));
   data.SetName(string.Format("{0}(Foo=bbb)", testName)); 
   yield return data; 
}

这意味着我的测试现在从NCrunch,TeamCity等发出

Test1(Foo=aaa)
Test1(Foo=bbb)
Test2(Foo=aaa)
Test2(Foo=bbb) 

这至少比完全无用的默认值更好。

答案 2 :(得分:1)

好吧,如果你幸运使用.NET 4.5,你可以在扩展TestCaseSource的新TestCaseSourceEx属性的构造函数的最后一个参数上使用[CallerMemberName]属性,它将在属性构造函数中提供测试方法名称。 。

这是一个工作样本:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestCaseSourceEx : TestCaseSourceAttribute
{
    public TestCaseSourceEx(Type sourceType, string sourceName, [CallerMemberName] string methodName = null)
        : base(sourceType, sourceName)
    {

    }
    public TestCaseSourceEx(string sourceName, [CallerMemberName] string methodName = null)
        : base(sourceName)
    {

    }
}

[TestFixture]
public class SampleTests
{
    public IEnumerable List = new[] { new string[] { "test-username", "test-password" } };

    [Test, TestCaseSourceEx("List")]
    public void SampleTests_LoginTest(string username, string password)
    {

    }
}

答案 3 :(得分:1)

经过长时间的谷歌搜索后,我发现我的解决方案比上面发布的解决方案更容易:

第一。在测试用例中,我添加了另一个参数:string testName:

+

第二。在TestCaseData中我添加了另一个参数,它显示了Foo对象的唯一属性,例如。名称

"script": "doc['userPermissions.id'].values + doc['pSPermissions.id'].values",

在NUnit跑步者中,结果显示如下:

[Test, TestCaseSource("TestData")] 
public void Test1(string testName, Foo foo)
{
    // test 1
}

[Test, TestCaseSource("TestData")] 
public void Test2(String testName, Foo foo)
{
    // test 2
}

这使测试在输出窗口中分开,而我仍然能够确切地看到正在运行的测试。

答案 4 :(得分:-1)

这个怎么样?

[TestCase("aaa")] 
[TestCase("bbb")] 
public void MainTest(string str)
{
  Assert.DoesNotThrow(()=> Test1(new Foo(str)));
  Assert.DoesNotThrow(()=> Test2(new Foo(str)));
}

public void Test1(Foo foo)
{
    // test 1
}

public void Test2(Foo foo)
{
    // test 2
}

UPD:

[TestCase("aaa")] 
[TestCase("bbb")] 
public void Test1(string str)
{
    var foo = new Foo(str);
    // rest of the test
}

[TestCase("aaa")] 
[TestCase("bbb")] 
public void Test2(string str)
{
    var foo = new Foo(str);
    // rest of the test
}