使用TextFixtureAttribute设置测试用例源

问题描述 投票:0回答:1

我创建了以下测试夹具模板,以测试自定义类的Equals方法。

class TestTemplate<X, Y>
{
    public virtual void Reflexivity(X x)
    {
        bool isEqual = x.Equals(x);
        Assert.IsTrue(isEqual);
    }

    public virtual void Symmetry(X x, Y y)
    {
        bool xy = x.Equals(y);
        bool yx = y.Equals(x);
        Assert.AreEqual(xy, yx);
    }

    public virtual void Transitivity(X x, Y y, Y z)
    {
        bool xy = x.Equals(y);
        bool yz = y.Equals(z);
        bool xz = x.Equals(z);
        Assert.IsTrue(!(xy && yz) || xz);
    }

    public virtual void NullTest(X x)
    {
        bool isEqual = x.Equals(null);
        Assert.IsFalse(isEqual);
    }

    public virtual void EqualTest(X x, Y equivalent)
    {
        bool isEqual = x.Equals(equivalent);
        Assert.IsTrue(isEqual);
    }

    public virtual void InqualTest(X x, Y nonequivalent)
    {
        bool isEqual = x.Equals(nonequivalent);
        Assert.IsFalse(isEqual);
    }
}

现在,我正在寻找使用模板的最佳方法。

1个衍生测试夹具

可以继承模板并使用TestCaseSourceAttribute提供一组测试用例。

[TestFixture]
class ConcreteTest : TestTemplate<MyClass, MyClass>
{
    [TestCaseSource(typeof(ConcreteTestSource), "ReflexivitySet")]
    public override void Reflexivity(MyClass x) => base.Reflexivity(x);

    [TestCaseSource(typeof(ConcreteTestSource), "EqualitySet")]
    [TestCaseSource(typeof(ConcreteTestSource), "InequalitySet")]
    public override void Symmetry(MyClass x, MyClass y) => base.Symmetry(x, y);

    [TestCaseSource(typeof(ConcreteTestSource), "TransitivitySet")]
    public override void Transitivity(MyClass x, MyClass y, MyClass z) => base.Transitivity(x, y, z);

    [TestCaseSource(typeof(ConcreteTestSource), "ReflexivitySet")]
    public override void NullTest(MyClass x) => base.NullTest(x);

    [TestCaseSource(typeof(ConcreteTestSource), "EqualitySet")]
    public override void EqualTest(MyClass x, MyClass equivalent) => base.EqualTest(x, equivalent);

    [TestCaseSource(typeof(ConcreteTestSource), "InqualitySet")]
    public override void InqualTest(MyClass x, MyClass nonequivalent) => base.InqualTest(x, nonequivalent);
}

它可以工作,但是需要为每个Equals实现定义一个单独的测试治具类。

2个灯具类的用法

另一种方法是直接将TestCaseSourceAttribute应用于基本夹具方法。

[TestFixture]
class EqualityTests
{
    [TestCaseSource(typeof(Test1Source), "ReflexivitySet")]
    [TestCaseSource(typeof(Test2Source), "ReflexivitySet")]
    [TestCaseSource(typeof(Test3Source), "ReflexivitySet")]
    public virtual void Reflexivity(object x)
    {
        bool isEqual = x.Equals(x);
        Assert.IsTrue(isEqual);
    }

    // Symmetry, Transitivity, EqualTest, InqualTest and NullTest methods definition here
}

生成的代码更加简洁,也可以使用。但是我想进一步减少代码。我相信可以只指定一次测试用例源。

3尝试使用夹具构造器设置测试数据源

在下一步中,我尝试通过TestFixtureAttribute的参数将源类型传递给夹具构造器来标识测试数据源。想法是使用Fixture字段或属性存储类型,然后在sourceTypeTestCaseSourceAttribute参数中使用它。

[TestFixture(typeof(Test1Source), TypeArgs = new Type[] { typeof(MyClass), typeof(MyClass) })]
[TestFixture(typeof(Test2Source), TypeArgs = new Type[] { typeof(ClassA), typeof(ClassA) })]
[TestFixture(typeof(Test3Source), TypeArgs = new Type[] { typeof(ClassA), typeof(ClassB) })]
class EqualityTests<X, Y>
{
    private Type _sourceType;

    public EqualityTests(Type sourceType)
    {
        _sourceType = sourceType;
    }

    [TestCaseSource(_sourceType, "SymmetrySet")]
    public virtual void Symmetry(X x, Y y)
    {
        bool xy = x.Equals(y);
        bool yx = y.Equals(x);
        Assert.AreEqual(xy, yx);
    }

    // Reflexivity, Transitivity, EqualTest, InqualTest and NullTest methods definition here
}

当然,该代码不起作用,因为sourceTypeTestCaseSourceAttribute属性需要常量或typeof表达式。

4尝试使用参数化的测试用例源

然后,我尝试使用中间参数化来源,该来源选择具体来源并从其中获取测试用例。它与先前的解决方案类似,但是使用methodParamsTestCaseSourceAttribute参数。

[TestFixture(typeof(Test1Source), TypeArgs = new Type[] { typeof(MyClass), typeof(MyClass) })]
[TestFixture(typeof(Test2Source), TypeArgs = new Type[] { typeof(ClassA), typeof(ClassA) })]
[TestFixture(typeof(Test3Source), TypeArgs = new Type[] { typeof(ClassA), typeof(ClassB) })]
class EqualityTests<X, Y>
{
    private Type _sourceType;

    public EqualityTests(Type sourceType)
    {
        _sourceType = sourceType;
    }

    [TestCaseSource("GetSymmetryTestSet", new object[] { _sourceType })]
    public virtual void Symmetry(X x, Y y)
    {
        bool xy = x.Equals(y);
        bool yx = y.Equals(x);
        Assert.AreEqual(xy, yx);
    }

    public static IEnumerable<TestCaseData> GetSymmetryTestSet(Type sourceType)
    {
        // return Symmetry member value of the sourceType
    }

    // Reflexivity, Transitivity, EqualTest, InqualTest and NullTest methods definition here
}

但是该解决方案也由于相同的原因而行不通:无法在methodParamsTestCaseSourceAttribute参数内使用灯具实例的非静态成员。

问题

因此,我想提高工作解决方案(2)的可重用性和可伸缩性。它不需要为每个Equals实现定义一个新的夹具,也不必在几个地方指定相同的测试用例源。我希望有可能,但是我坚持要实现它。请让我知道您是否有解决问题的建议或建议。

c# nunit nunit-3.0
1个回答
1
投票
[Test] public void Test1() { var x = new SomeType1() AssertReflexivity(x); } [Test] public void Test2() { var x = new SomeType1(); var y = new SomeType2(); AssertReflexivity(x, y); }

几点
如果大约是同一类型

您可以在课堂上使用一种类型

class TestHelpers { public static void AssertReflexivity<T>(T x) { bool isEqual = x.Equals(x); Assert.IsTrue("Add a good message here, otherwise test output may be hard to read"); } public static AssertSymmetry<T>(T x, T y)

  1. 如果您比较两个对象的所有属性都设置为null怎么办?他们反身吗?
如果这涉及不同类型
  1. 它取决于Equals是如何被覆盖/实现的-这些测试在许多与类型之间的关系无关,而与数据设置没有太大关系的不同情况下可以通过/失败。
  2. 反身应该使用不同的类型吗?
      如果您比较两个对象的所有属性都设置为null怎么办?他们反身吗?

© www.soinside.com 2019 - 2024. All rights reserved.