MsTest不支持在测试基类中定义TestMethod吗? [英] Is defining TestMethod's in test base classes not supported by MsTest?

查看:94
本文介绍了MsTest不支持在测试基类中定义TestMethod吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题涉及一种通用的单元测试技术,该技术可能具有非常有用的广泛适用场景.但是,通过一个例子来更好地说明我的问题会更容易理解.

This question concerns a general unit test technique with a potentially very useful wide range of applicable scenarios. But it is easier to understand with an example to illustrate my question better.

比方说,我想测试所有覆盖Equals()的类型是否正确执行.由于Equals()System.Object中被定义为虚拟的,因此各种各样的类型可能会改变该行为.每个这样做的类型都必须进行测试,以确保新行为遵循该方法的调用者的隐式期望.专门针对Equals(),如果重写该方法,则新实现必须确保两个相等的对象也具有相同的哈希码,如System.Object.GetHashCode()所定义.

Let's say I want to test that all types that override Equals() does so correctly. Since Equals() is defined as virtual in System.Object, a wide range of types may change that behavior. Each type that does so, will have to have tests to make sure that the new behavior follows the implicit expectations of a caller of that method. Specifically for Equals(), if you override that method the new implementation must make sure that two equal objects also have equal hash codes, as defined by System.Object.GetHashCode().

要执行此操作,将需要多个测试类,并且它们都将测试所有这些类型的行为是否具有相同的一致性.

Thus to enforce this, multiple test classes will be needed and they will all test for the same consistency of behavior across all these types.

为避免重新键入测试这种类型所需的所有TestMethod,我改为定义一个如下所示的基本测试类,并使这些测试类都继承相同的行为测试套件:

To avoid having to re-type all the TestMethods required to test such a type I instead define a base test class that looks like below, and have those test classes all inherit the same behavior test suite:

/// <summary>
/// Test fixture base class for testing types that overrides Object.Equals()
/// </summary>
/// <typeparam name="T">The production type under test</typeparam>
public abstract class EqualsFixtureBase<T>
{
    #region Equals tests

    protected static void CompareInstances(T inst1, T inst2, bool expectedEquals)
    {
        Assert.AreEqual(expectedEquals, inst1.Equals((T)inst2));
        Assert.AreEqual(expectedEquals, inst1.Equals((object)inst2));
        if (expectedEquals)
        {
            // equal instances MUST have identical hash codes
            // this is a part of the .NET Equals contract
            Assert.AreEqual(inst1.GetHashCode(), inst2.GetHashCode());
        }
        else
        {
            if (inst2 != null)
            {
                Assert.AreNotEqual(inst1.GetHashCode(), inst2.GetHashCode());
            }
        }
    }

    /// <summary>
    /// Creates version 1 instance of the type under test, not 'Equal' to instance 2.
    /// </summary>
    /// <returns>An instance created with properties 1.</returns>
    protected abstract T CreateInstance1();

    /// <summary>
    /// Creates version 2 instance of the type under test, not 'Equal' to instance 1.
    /// </summary>
    /// <returns>An instance created with properties 2.</returns>
    protected abstract T CreateInstance2();

    /// <summary>
    /// Creates an instance equal to the version 1 instance, but not the identical
    /// same object.
    /// </summary>
    /// <returns>An instance created with properties equal to instance 1.</returns>
    protected abstract T CreateInstanceThatEqualsInstance1();

    [TestMethod]
    public void Equals_NullOrDefaultValueTypeInstance()
    {
        T instance = CreateInstance1();
        CompareInstances(instance, default(T), false);
    }

    [TestMethod]
    public void Equals_InstanceOfAnotherType()
    {
        T instance = CreateInstance1();
        Assert.IsFalse(instance.Equals(new object()));
    }

    [TestMethod]
    public void Equals_SameInstance()
    {
        T slot1 = CreateInstance1();
        CompareInstances(slot1, slot1, true);
    }

    [TestMethod]
    public void Equals_EqualInstances()
    {
        T slot1 = CreateInstance1();
        T slot2 = CreateInstanceThatEqualsInstance1();
        CompareInstances(slot1, slot2, true);
        CompareInstances(slot2, slot1, true);
    }

    [TestMethod]
    public void Equals_NonEqualInstances()
    {
        T slot1 = CreateInstance1();
        T slot2 = CreateInstance2();
        CompareInstances(slot1, slot2, false);
        CompareInstances(slot2, slot1, false);
    }

    #endregion Equals tests
}

然后,我可以为覆盖Equals()的每种类型重用这些TestMethod.例如,这将是用于测试System.String类型正确实现Equals()的测试类定义.

I can then reuse these TestMethods for each type overriding Equals(). For instance, this would be the test class definition for testing that the System.String type implements Equals() correctly.

[TestClass]
public class ExampleOfAnEqualsTestFixture : EqualsFixtureBase<string>
{
    [TestMethod]
    public void Foo()
    {
        Assert.IsTrue(true);
    }

    protected override string CreateInstance1()
    {
        return "FirstString";
    }

    protected override string CreateInstance2()
    {
        return "SecondString";
    }

    protected override string CreateInstanceThatEqualsInstance1()
    {
        return "FirstString";
    }
}

这也可以进一步扩展.例如,对于重载==和!=运算符的类型,可以定义第二个抽象测试基类(即EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>),该基类测试这些运算符的实现不仅正确,而且与扩展定义一致Equals()GetHashCode().

This can also be extended further. For instance, for types that overload the == and != operators, a second abstract test base class can be defined (i.e. EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>) that tests that the implementation of those operators are not only correct, but also consistent with the extended definitions of Equals() and GetHashCode().

我可以使用NUnit进行此操作,但是使用MsTest时会遇到问题.

I can do this using NUnit, but when using MsTest I get problems.

a)Visual Studio 2010仅发现Foo()测试方法,而不发现继承的测试方法,因此它无法运行它们.似乎Visual Studio测试加载程序不会遍历测试类的继承层次结构.

a) Visual Studio 2010 only discovers the Foo() test method, not the inherited test methods so it can't run them. It seems the Visual Studio test loader does not walk the inheritance hierarchy of the test class.

b)当我在TFS中检入这些类型时,TFS找到抽象的EqualsFixtureBase类型,并认为它是要运行的测试类.但是,由于无法创建它,因此无法运行它并将该类型的测试标记为不确定的-这会导致测试运行失败,从而导致生成(!).

b) When I check in these types in TFS, TFS finds the abstract EqualsFixtureBase type and thinks it is a test class to be run. But since it can not be created, it can't run it and labels the tests in that type as inconclusive - which fails the test run, and thus the build (!).

是否有解决此问题的方法,或者这是MsTest和Visual Studio的限制吗?

Is there a way to get around this, or is this a limitation of MsTest and Visual Studio?

如果是这样,是否可以在VS/TFS的路线图中解决此问题?

If so, is fixing this in the roadmap for VS/TFS ??

这将非常有用,特别是在测试实现接口或属于继承层次结构的生产类型时,如果某些类型的成员具有语义合同类型"属性或不变量-如果有意义的话.

This would be very useful, especially when testing production types that implement an interface, or are part of an inheritance hierarcy, where certain members have semantic 'contract type' properties or invariants - if that makes sense.

基本上,不对此提供支持会阻止我重构测试代码以删除重复项.

Basically, not having support for this inhibits me from refactoring my test code to remove duplication.

谢谢

我发现此链接到一个MSDN博客,它显示以下内容

I found this link to one of the MSDN blogs, it says the following

在Whidbey中,缺少对测试类继承的支持.在Nunit中,它得到了完全支持.这将在Orcas中得到纠正."

"In Whidbey, support for test class inheritance was missing. In Nunit, it is fully supported. This will be rectified in Orcas."

那是三年前写的.为什么还没有添加呢?我不明白,这样做是有正当理由的,在我看来,这将是一个很小的变化.还是我只是没有在这里跳正确的篮球?

That was written over three years ago. Why has this not been added yet? I don't get it, there are legitimate reasons to have this and in my mind it would be a minor change. Or am I just not jumping the right hoops here?

推荐答案

使用VS 2010我没有看到与您相同的行为.当我将您的2个类复制到测试项目中并进行编译时,我得到了输出:

Using VS 2010 I am not seeing the same behavior as you are. When I copied your 2 classes into a test project and compiled it I got the output:

UTA004: Illegal use of attribute...The TestMethodAttribute can be 
defined only inside a class marked with the TestClass attribute

所以我标记了 EqualsFixutureBase :

[TestClass]
public abstract class EqualsFixtureBase<T>
{
...
}

现在,它会编译而不会发出警告,当我为 ExampleOfAnEqualsTestFixture 选择运行测试时,它将运行Foo,所有5个继承的equals测试.同样,当我复制 ExampleOfAnEqualsTestFixture 并将其用于 int 并运行解决方案的测试时,我看到示例字符串类和示例int类.

Now it compiles without warning and when I select run tests for ExampleOfAnEqualsTestFixture it runs Foo and all 5 of the inherited equals tests. Also when I copy the ExampleOfAnEqualsTestFixture and use it for int and run the tests for the solution I see all 5 inherited tests running (and passing) for the example string class and the example int class.

除了示例之外,您是否还在做其他可能导致问题的事情?

Are you doing something in addition to your example which might be causing your problem?

这篇关于MsTest不支持在测试基类中定义TestMethod吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆