Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 访问TestCaseSource中的NUnit测试名称_C#_Unit Testing_Nunit - Fatal编程技术网

C# 访问TestCaseSource中的NUnit测试名称

C# 访问TestCaseSource中的NUnit测试名称,c#,unit-testing,nunit,C#,Unit Testing,Nunit,我有一系列的测试,我想使用相同的测试用例数据进行一系列不同的测试 例如: 这导致了一系列的测试,报告如下: 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.

我有一系列的测试,我想使用相同的测试用例数据进行一系列不同的测试

例如:

这导致了一系列的测试,报告如下:

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”失败了什么,这就没有多大意义

如果我这样设置名称:

   data = new TestCaseData(new Foo("aaa"));
   data.SetName("foo=aaa");
   yield return data; 
foo=aaa   
foo=bbb  
foo=aaa  
foo=bbb 
…然后我所有的测试结果都是这样的:

   data = new TestCaseData(new Foo("aaa"));
   data.SetName("foo=aaa");
   yield return data; 
foo=aaa   
foo=bbb  
foo=aaa  
foo=bbb 
因此,我试图找出如何获得当前的测试方法名。这似乎是通过TestContext完成的

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

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

如何

[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:


这不是一个完美的答案,但到目前为止,我找到的最好的解决方案是为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) 

这至少比完全无用的违约要好

好吧,如果您幸运地使用了.NET 4.5,您可以在扩展TestCaseSource的新TestCaseSourceX属性的构造函数的最后一个参数上使用[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)
    {

    }
}

经过长时间的谷歌搜索,我找到了比上面发布的解决方案简单得多的解决方案:

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

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

[Test, TestCaseSource("TestData")] 
public void Test2(String testName, Foo foo)
{
    // test 2
}
第二。在TestCaseData中,我添加了另一个参数,它显示了Foo对象的唯一属性,例如name

private static IEnumerable TestData() 
{
   TestCaseData data; 

   Foo data1 = new Foo("aaa");
   data = new TestCaseData(data1.name, data1);
   yield return data; 

   Foo data2 = new Foo("bbb");
   data = new TestCaseData(data2.name, data2);
   yield return data; 
}
在NUnit runner中,结果如下所示:

Namespace.That.Is.Very.Long.TestClass.Test1("aaa", Namespace.That.Is.Very.Long.Foo)
Namespace.That.Is.Very.Long.TestClass.Test1("bbb", Namespace.That.Is.Very.Long.Foo)  

这使得测试在输出窗口中独立,而我仍然能够准确地看到正在运行的测试。

属性
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;
}
将生成以下输出:

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

有关NUnit的字符串格式化功能的更多信息,请使用


2个类可负责此操作和
TestNameGenerator
方法
.GetDisplayName()

您不使用失败的断言提供的信息、缺少异常等的原因是什么?我可以使用失败的断言提供的信息,但它不会告诉我提供了什么测试用例数据。此外,在TeamCity等CI平台上,具有相同输出名称的测试用例被聚合并显示为一个。“Test{x}运行了7次,失败了1次”(或类似的)@JamesFaix对我来说,
TestContext.CurrentContext.Test.Name
工作正常,在所提供的案例中输出
foo=aaa
,所以我认为这是固定的。因此,您可以只使用
SetName
+
TestContext.CurrentContext.Test.Name
。这可能是版本上的差异。我在NUnit3.6上。从我尝试过的每个实验来看,当测试运行者读取测试用例列表时,测试上下文数据不可用。在测试开始之前读取案例,因此还没有任何测试上下文。您可以访问
TestContext.CurrentContext
,但大多数属性都为null,在这种特殊情况下,我在尝试引用测试用例列表属性中的
TestContext.CurrentContext.Test.Name
时会遇到
NullReferenceException
。可能还取决于运行程序。我使用了Resharpers测试运行程序和nuget包中的最新版本nunit(我想是3.7.1)。它正确显示所有测试名称,并且
Console.WriteLine(TestContext.CurrentContext.test.Name)
将测试名称写入输出,没有任何异常。PS:刚降级到3.6.0,它在Resharper runner上仍然可以正常工作。这只会让我一次看到一个测试失败。是的,这不是你想要的。根据我在单元测试方面的经验,最佳实践是使单元测试尽可能明确。即使这意味着在不同的测试中重复一些代码。我知道这听起来有悖直觉,但在测试中,我更喜欢看一个测试,并了解那里发生了什么。因此,按照这个建议,您可以为每个测试复制测试用例。我编辑了答案。我们不使用TestCase,因为我们想要传递的实际内容更复杂(在本例中,是一个方法委托,但原则是用于无法在属性中传递的内容)。我添加了一个答案,其中显示了我实际使用的解决方法。这不太好,但比我找到的其他选择要好。谢谢——在为这个问题绞尽脑汁两天后,我也这样做了。这是对测试用例参数的滥用,如果许多测试使用相同的数据源,可能需要对测试用例签名进行大量更改,但在没有任何其他有效方法的情况下,它对我有效。您可以从要测试的
Foo
实例的静态列表开始,然后在
TestData\u-Base
方法中使用它从它们生成
TestCaseData
实例。这将减少必须在Foo构造函数和
SetName
方法中指定“aaa”的重复。(请参阅)我看不出这如何帮助您将
methodName
放入TestCaseData Name属性中……除非我遗漏了一些明显的内容??CallerMemberName属性参数引入了方法名称。在4.5中引入。以前唯一的选择是深入调用堆栈。如果您观察代码,我们不会调用构造函数参数,它是由运行时调用的。我理解这一部分,我不理解的是,现在TestCaseSourceAttribute类中有可用的
methodName
,我如何使用它来设置测试的名称?据我所知,我需要c