NUnit:如何从非静态方法传递TestCaseData?

时间:2016-09-07 09:01:37

标签: c# unit-testing junit nunit nunit-3.0

我的测试失败的原因是: 消息:TestCaseSourceAttribute上指定的sourceName必须引用静态字段,属性或方法。

这是我的代码:

const double MAX_DELTA = 0.01;
Qv_ges qv_ges_NE;
double Sum_Qv_ges_R_FL;
Qv_ges Qv_ges_Quer;

[SetUp]
public void init()
{
    qv_ges_NE = Din1946.Calc_Qv_ges_NE(205.7d);
    Sum_Qv_ges_R_FL = 15d + 15d + 15d + 15d + 15d + 10d + 10d + 10d + 10d + 10d + 10d + 10d;
    Qv_ges_Quer = Din1946.Calc_Qv_ges_Quer(qv_ges_NE, Sum_Qv_ges_R_FL);
}

public IEnumerable<TestCaseData> TestCases_A()
{
        yield return new TestCaseData(72.5, Qv_ges_Quer.FL.Value, MAX_DELTA);
        yield return new TestCaseData(169.17, Qv_ges_Quer.RL.Value, MAX_DELTA);
        yield return new TestCaseData(241.67, Qv_ges_Quer.NL.Value, MAX_DELTA);
        yield return new TestCaseData(314.17, Qv_ges_Quer.IL.Value, MAX_DELTA);
    }


    [TestCaseSource("TestCases_A")]
public void MethodA(double expected, double value, double latitude)
      { Assert.AreEqual(expected, value, latitude);}

我只使用静态测试用例方法,但现在我需要以下数据: Qv_ges_Quer.IL.ValueQv_ges_Quer.FL.Value ....所以我删除了静态

如何使用非静态测试用例?我还通过调试注意到它最初没有进入SetUp

这是我想要重新设置的旧代码,mybe你知道另一种/更好的方式然后上面的方式:

public void MethodA(){
  Qv_ges qv_ges_NE = Din1946.Calc_Qv_ges_NE(205.7d);

  double Sum_Qv_ges_R_FL = 15d + 15d + 15d + 15d + 15d + 10d + 10d + 10d + 10d + 10d + 10d + 10d;
  Qv_ges Qv_ges_Quer = Din1946.Calc_Qv_ges_Quer(qv_ges_NE, Sum_Qv_ges_R_FL);

  Assert.AreEqual(72.5, Qv_ges_Quer.FL.Value, MAX_DELTA);
  Assert.AreEqual(169.17, Qv_ges_Quer.RL.Value, MAX_DELTA);
  Assert.AreEqual(241.67, Qv_ges_Quer.NL.Value, MAX_DELTA);
  Assert.AreEqual(314.17, Qv_ges_Quer.IL.Value, MAX_DELTA);
}

2 个答案:

答案 0 :(得分:7)

根据设计,TestCaseSourceAttribute使用的方法,属性或字段必须是静态的。这是为了避免在加载测试时实例化fixture类。你的夹具只在我们开始运行时才被实例化 - 在GUI的情况下,每次我们开始运行 - 它的寿命只有运行夹具所需的时间。

在您的情况下,您似乎发现可以使用静态方法。如果可能的话,这是最好的。

此处使用实例方法的唯一方法是使用构造函数TestCaseSourceAttribute(Type sourceType),其中sourceType实现IEnumerable并直接返回测试用例数据。如果您使用此功能,我建议您使用TestFixture中的其他类。这不是绝对必要的。如果使用相同的类,则会在加载时和运行时创建不同的实例,这些实例彼此之间没有任何关联。许多开发人员最终都对此感到困惑,并试图在加载时将状态置于测试之后。那不会起作用。

答案 1 :(得分:3)

‍♀️ 僵尸反应,但迟到总比没有好。

另一种实现此目的的方法是让您的测试用例数据源返回一个函数对象,该函数对象接受您需要的非静态成员作为其参数。然后您的测试调用它来创建您希望NUnit可以传递给您的数据。

在您的情况下,看起来像这样:

private static IEnumerable<TestCaseData> GetTestDataA()
{
    yield return new TestCaseData(72.5,   new Func<Qv_ges, double>( qvGesQuer => qvGesQuer.FL.Value ), MAX_DELTA);
    yield return new TestCaseData(169.17, new Func<Qv_ges, double>( qvGesQuer => qvGesQuer.RL.Value ), MAX_DELTA);
    yield return new TestCaseData(241.67, new Func<Qv_ges, double>( qvGesQuer => qvGesQuer.NL.Value ), MAX_DELTA);
    yield return new TestCaseData(314.17, new Func<Qv_ges, double>( qvGesQuer => qvGesQuer.IL.Value ), MAX_DELTA);
}

[TestCaseSource( nameof(GetTestDataA) )]
public void MethodA( double expected, Func<Qv_ges, double> getValue, double latitude)
{ 
    Assert.AreEqual( expected, getValue( Qv_ges_Quer ), latitude );
}

如果您需要多个参数,请将它们添加到函子和lambda的参数中,或者考虑改为传入this。如果需要多个返回值,请使函数对象返回一个元组:

new Func<Qv_ges, (double, double)>( qvGesQuer => (qvGesQuer.RL.Value, qvGesQuer.IL.Value) )

另一种方法是传递nameof()字符串作为测试参数,并使用反射来获取那些参数的值。