Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.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# 如何从TestContext获取当前参数值?_C#_Unit Testing_Nunit - Fatal编程技术网

C# 如何从TestContext获取当前参数值?

C# 如何从TestContext获取当前参数值?,c#,unit-testing,nunit,C#,Unit Testing,Nunit,我有一个单元测试: [Test] [TestCaseSource(typeof(AllExampleEnumValues))] public void GivenSth_WhenSth_ThenSth(ExampleEnum enumValue) { // Given var givenState = BaseClassProperty; // property from fixture's base class systemUnderTest.SetSomeState(

我有一个单元测试:

[Test]
[TestCaseSource(typeof(AllExampleEnumValues))]
public void GivenSth_WhenSth_ThenSth(ExampleEnum enumValue)
{
    // Given
    var givenState = BaseClassProperty; // property from fixture's base class
    systemUnderTest.SetSomeState(givenState);

    // When
    var result = systemUnderTest.AnswerAQuestion(
        "What's the answer to"
        + " the Ultimate Question of Life,"
        + " the Universe,"
        + " and Everything?");

    // Then
    Assert.That(result, Is.EqualTo(42));
}
其中
AllExampleEnumValues
如下所示:

public class AllGranularities : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        return Enum
            .GetValues(typeof(ExampleEnum))
            .Cast<ExampleEnum>()
            .Select(ee => new object[] { ee })
            .GetEnumerator();
    }
}
如何在运行时在
BaseClassProperty
中获取
enumValue
参数的当前值,而不将其更改为函数并将
enumValue
作为参数传递

我知道我可以走到stackframe并从那里阅读它(不,实际上,我不能:),但也许有一个更优雅的解决方案

我需要这一点来提高测试的可读性,
enumValue
会隐式地影响读取
BaseClassProperty
的结果,这一事实不会降低可读性,因为在我的领域中,这种依赖性对每个人来说都是显而易见的

我一直在研究
TextContext
类,但它在这个上下文中似乎没有什么用处。正如在注释中提到的,该值存在于测试的名称中——但是这里不接受从字符串解析该值,因为有时我们使用多个参数和通用测试用例

另一个线索导致使用
IApplyToTest
属性。但是,这需要将此属性应用于每个测试


最后,另一个线索导致使用
ITestAction
,从内部我可以访问
ITest
接口,该接口提供了一个
TestMethod
实例。它具有
参数
属性!不幸的是,它是私有的。

我已经设法创建了以下解决方法:

[AttributeUsage(AttributeTargets.Class)]
public class TrackEnumValueActionAttribute : Attribute, ITestAction
{
    public ActionTargets Targets
    {
        get
        {
            return ActionTargets.Test;
        }
    }

    public void AfterTest(ITest test)
    {
    }

    public void BeforeTest(ITest test)
    {
        if (!(test.Fixture is ICurrentExampleEnumValueHolder))
        {
            return;
        }

        var arguments = GetArgumentsFromTestMethodOrNull(test);

        if (arguments == null)
        {
            return;
        }

        var eumValue = GetEnumValueFromArgumentsOrNull<ExampleEnum>(arguments);

        (test.Fixture as ICurrentExampleEnumValueHolder).CurrentEnumValue = enumValue;
    }

    private object[] GetArgumentsFromTestMethodOrNull(ITest test)
    {
        return test
            .GetType()
            .GetProperty("Arguments", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
            ?.GetValue(test) as object[];
    }

    private T? GetEnumValueFromArgumentsOrNull<T>(object[] arguments) where T : struct
    {
        return arguments
            .Where(a => a.GetType().Equals(typeof(T)))
            .Select(a => (T?)a)
            .FirstOrDefault();
    }
}
[AttributeUsage(AttributeTargets.Class)]
公共类TrackEnumValueActionAttribute:属性,iTestation
{
公共行动目标
{
得到
{
返回操作目标。测试;
}
}
公共空隙后测试(ITest测试)
{
}
测试前公共无效(ITest测试)
{
如果(!(test.Fixture为ICurrentExampleEnumValueHolder))
{
返回;
}
变量参数=GetArgumentsFromTestMethodorFull(测试);
if(参数==null)
{
返回;
}
var eumValue=GetEnumValueFromArgumentsOrNull(参数);
(test.Fixture作为ICurrentExampleEnumValueHolder)。CurrentEnumValue=enumValue;
}
私有对象[]GetArgumentsFromTestMethodOrNull(ITest测试)
{
回归试验
.GetType()
.GetProperty(“参数”,System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
?作为对象的GetValue(测试)[];
}
私有T?GetEnumValueFromArgumentsOrNull(对象[]参数),其中T:struct
{
返回参数
其中(a=>a.GetType().Equals(typeof(T)))
.选择(a=>(T?)a)
.FirstOrDefault();
}
}
将此属性应用于fixture的基类,并实现
ICurrenteExampleEnumValueHolder
接口就可以做到这一点——我的属性(存在于接口中)的值具有一个取决于测试方法调用参数的值


不幸的是,NUnit中的
TestMethod
类的
Arguments
属性是内部的,因此存在丑陋的反射解决方案。我发布了一个关于这件事的问题:

你需要这个值做什么?将其作为字符串而不是实际值是否可以?@thomasleveque我知道它存在于测试名称中。但是,我们有时会使用多个参数,解析这样的字符串中的值太复杂,也不太安全。谢谢你的建议!我认为你最好的选择是在NUnit repo中请求该功能。实现起来可能不太复杂。我认为如果不说明如何用NUnit术语翻译给定的/When/Then方法,就不可能回答这个问题。您单独指出它们是您自己设计的方法。@Charlie不,它们完全不相关。由于它们引起了一些混乱,我已经从代码片段中删除了它们。它们只是对当前代码片段的巧妙包装。
[AttributeUsage(AttributeTargets.Class)]
public class TrackEnumValueActionAttribute : Attribute, ITestAction
{
    public ActionTargets Targets
    {
        get
        {
            return ActionTargets.Test;
        }
    }

    public void AfterTest(ITest test)
    {
    }

    public void BeforeTest(ITest test)
    {
        if (!(test.Fixture is ICurrentExampleEnumValueHolder))
        {
            return;
        }

        var arguments = GetArgumentsFromTestMethodOrNull(test);

        if (arguments == null)
        {
            return;
        }

        var eumValue = GetEnumValueFromArgumentsOrNull<ExampleEnum>(arguments);

        (test.Fixture as ICurrentExampleEnumValueHolder).CurrentEnumValue = enumValue;
    }

    private object[] GetArgumentsFromTestMethodOrNull(ITest test)
    {
        return test
            .GetType()
            .GetProperty("Arguments", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
            ?.GetValue(test) as object[];
    }

    private T? GetEnumValueFromArgumentsOrNull<T>(object[] arguments) where T : struct
    {
        return arguments
            .Where(a => a.GetType().Equals(typeof(T)))
            .Select(a => (T?)a)
            .FirstOrDefault();
    }
}