我希望我的基于NUnit
框架的单元测试在Visual Studio测试资源管理器中更具人性化。
例如,我最好不要使用Test_Case_1
或TestCase1
,而是使用Test Case #1, Category: First, Category: Second
之类的内容(通过分配来自[Category]
属性的值),空格和字符不是在方法名称中允许。
我知道它在xUnit
中可能是开箱即用的,但我无法参与其中,因为我使用的是我无法使用xUnit
框架实现的自定义。 / p>
是否可以使用NUnit
重写单元测试显示名称?到目前为止,我可以看到,FullName
的{{1}}字段有私人制定者。
是否有其他方式或方法更改TestDetail
测试的显示名称?
答案 0 :(得分:4)
如果您使用参数化测试,则支持此功能,您可以在添加TestName
属性时指定TestCase
。
如果您没有使用TestCase,那么您可以将其用作不太理想的工作来实现您想要做的事情。所以你会像这样声明你的测试:
[TestCase(null,TestName="Test Case #1, Category: First, Category: Second")]
public void TestCase(object ignored)
这不是理想的,因为它不是程序化的,因此您必须手动键入测试名称,而不是从测试方法的属性生成它。您还必须将参数传递给方法,这是ignored
和null
的内容。当然,您可以开始使用参数化测试,在这种情况下,您将实际值传递给测试。
[TestCase(5,TestName="Test Case #1, Category: First, Category: Second")]
public void TestCase(int someInput) {
Assert.AreEqual(5, someInput);
}
答案 1 :(得分:3)
您可以创建自己的名称属性:
// I used the same namespace for convenience
namespace NUnit.Framework
{
public class NameAttribute : NUnitAttribute, IApplyToTest
{
public NameAttribute(string name)
{
Name = name;
}
public string Name { get; set; }
public void ApplyToTest(Test test)
{
test.Properties.Add("Name", Name);
}
}
}
然后将其用作常规NUnit属性(就像类别和描述一样)。
[Test, Name("My Awesome Test"), Category("Cool.Tests"), Description("All cool tests")]
public void Test313()
{
// Do something
}
您可以在TestContext中看到数据:
if (TestContext.CurrentContext.Test.Properties.ContainsKey("Name"))
{
name = TestContext.CurrentContext.Test.Properties.Get("Name") as string;
}
答案 2 :(得分:0)
我想以编程方式动态更改参数化 NUnit 测试的测试名称,即基于测试数据文件夹中的输入文件。
进行了几次调整,但效果很好:
[Test, TestCaseSource(nameof(GetSites))]
public void TestForEveryFile(object ignored, FileInfo testFile) {
// actual test using 'testFile'
}
public static IEnumerable<TestCaseData> GetSites()
{
foreach (string testFile in Directory.EnumerateFiles("TestData"))
{
FileInfo fileInfo = new FileInfo(testFile);
// Pass '' as first argument to TestCaseData to suppress the default test name
// (seems to be necessary even if TestName is set)
var testCase = new TestCaseData("", fileInfo)
{
// Use the short file name as test name.
// As dots (.) would indicate a test hierarchy, we replace them with '-'.
TestName = fileInfo.Name.Replace(".", "-")
};
yield return testCase;
}
}
答案 3 :(得分:0)
一种可能的方法是创建您自己的 TestAttribute
类并将 Name
实例的属性 NUnit.Framework.Internal.TestMethod
设置为您想要显示的任何文本(参见方法 TestAttribute.BuildFrom
下面的代码)。
请注意,此代码只不过是一个 hack。它可能会导致我没有想到的副作用。
using System;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Builders;
namespace NUnitTesting.Tests
{
[TestFixture(TestName = "Display name of Tests")]
public class Tests
{
[Test(DisplayName = "Display name of Test1")]
public void Test1()
{
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TestAttribute : NUnitAttribute, ISimpleTestBuilder, IApplyToTest, IImplyFixture
{
/// <summary>
/// The author of this test.
/// </summary>
public String Author { get; set; }
/// <summary>
/// Descriptive text for this test.
/// </summary>
public String Description { get; set; }
/// <summary>
/// The display name for this test.
/// </summary>
public String DisplayName { get; set; }
/// <summary>
/// Gets or sets the expected result.
/// Not valid if the test method has parameters.
/// </summary>
/// <value>The result.</value>
public Object ExpectedResult
{
get => this.expectedResult;
set
{
this.expectedResult = value;
this.hasExpectedResult = true;
}
}
/// <summary>
/// The type that this test is testing.
/// </summary>
public Type TestOf { get; set; }
#region IApplyToTest Members
/// <summary>
/// Modifies a test by adding a description, if not already set.
/// </summary>
/// <param name="test">The test to modify.</param>
public void ApplyToTest(Test test)
{
if (!(test.Method is Object))
{
throw new ArgumentException("This attribute must only be applied to tests that have an associated method.", nameof(test));
}
if (!test.Properties.ContainsKey(PropertyNames.Description) && this.Description != null)
test.Properties.Set(PropertyNames.Description, this.Description);
if (!test.Properties.ContainsKey(PropertyNames.Author) && this.Author != null)
test.Properties.Set(PropertyNames.Author, this.Author);
if (!test.Properties.ContainsKey(PropertyNames.TestOf) && this.TestOf != null)
test.Properties.Set(PropertyNames.TestOf, this.TestOf.FullName);
if (this.hasExpectedResult && test.Method.GetParameters().Length > 0)
test.MakeInvalid("The 'TestAttribute.ExpectedResult' property may not be used on parameterized methods.");
}
#endregion
#region ISimpleTestBuilder Members
/// <summary>
/// Builds a single test from the specified method and context.
/// </summary>
/// <param name="method">The method for which a test is to be constructed.</param>
/// <param name="suite">The suite to which the test will be added.</param>
public TestMethod BuildFrom(IMethodInfo method, Test suite)
{
TestCaseParameters parms = null;
if (this.hasExpectedResult)
{
parms = new TestCaseParameters();
parms.ExpectedResult = this.ExpectedResult;
}
var testMethod = this.builder.BuildTestMethod(method, suite, parms);
testMethod.Name = this.DisplayName;
return testMethod;
}
#endregion
private readonly NUnitTestCaseBuilder builder = new NUnitTestCaseBuilder();
private Object expectedResult;
private Boolean hasExpectedResult = false; // needed in case result is set to null
}
}
这样,至少 Visual Studio 测试资源管理器会显示“Test1 的显示名称”而不仅仅是“Test1”:
然而,ReSharper 的测试运行程序/资源管理器仍然使用该方法的名称: