Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.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# 在VisualStudio中控制单元测试的执行顺序_C#_Unit Testing_Visual Studio 2012 - Fatal编程技术网

C# 在VisualStudio中控制单元测试的执行顺序

C# 在VisualStudio中控制单元测试的执行顺序,c#,unit-testing,visual-studio-2012,C#,Unit Testing,Visual Studio 2012,好了,我已经找不到这方面的好消息了。 我有一系列的单元测试,它们调用一个静态类,该类一旦初始化,就会设置不能(或者我不希望)更改的属性 我的问题是我无法强制执行测试运行的设置顺序。如果可以的话,我可以以这样的方式运行它们,因为静态属性将以可靠的方式设置,并且我可以对它们进行断言,但不幸的是,Microsoft.VisualStudio.TestTools.UnitTesting框架只是以看似随机的顺序运行它们 所以,我在备注部分找到了这样一条:“这个属性不是由测试系统使用的,它是为用户定制的。”

好了,我已经找不到这方面的好消息了。 我有一系列的单元测试,它们调用一个静态类,该类一旦初始化,就会设置不能(或者我不希望)更改的属性

我的问题是我无法强制执行测试运行的设置顺序。如果可以的话,我可以以这样的方式运行它们,因为静态属性将以可靠的方式设置,并且我可以对它们进行断言,但不幸的是,Microsoft.VisualStudio.TestTools.UnitTesting框架只是以看似随机的顺序运行它们

所以,我在备注部分找到了这样一条:“这个属性不是由测试系统使用的,它是为用户定制的。”哈?那有什么用呢?他们是否希望我编写自己的测试包装器来利用这个惊人的属性(如果我想达到这个级别,我可以很容易地编写自己的属性…)

所以,别再唠叨了;总之,有没有办法控制单元测试运行的顺序

[TestMethod]
[Priority(0)]
等似乎不起作用,这是有道理的,因为微软说它不会

此外,请不要对“违反隔离”发表评论。TestClass隔离了我正在测试的内容,而不是单个的TestMethods。不管怎样,每个测试都可以独立运行,但它们不能以随机顺序一起运行,因为没有办法破坏静态类


哦,我还知道“有序测试”。

将您的测试合并到一个大型测试中会有效。为了使测试方法更具可读性,可以执行以下操作

[TestMethod]
public void MyIntegratonTestLikeUnitTest()
{
    AssertScenarioA();

    AssertScenarioB();

    ....
}

private void AssertScenarioA()
{
     // Assert
}

private void AssertScenarioB()
{
     // Assert
}

实际上,您遇到的问题建议您可能应该改进实现的可测试性

将您的测试合并到一个巨大的测试中会起作用。为了使测试方法更具可读性,可以执行以下操作

[TestMethod]
public void MyIntegratonTestLikeUnitTest()
{
    AssertScenarioA();

    AssertScenarioB();

    ....
}

private void AssertScenarioA()
{
     // Assert
}

private void AssertScenarioB()
{
     // Assert
}

实际上,您遇到的问题建议您可能应该改进实现的可测试性

既然您已经提到了VisualStudio测试框架提供的有序测试功能,我将忽略这一点。您似乎还意识到,为了测试这个静态类而试图完成的工作是一个“坏主意”,所以我将忽略这一点

相反,让我们把重点放在如何确保您的测试按照您想要的顺序执行。一个选项(由@gaog提供)是“一个测试方法,多个测试函数”,在标记有
TestMethod
属性的单个函数中,按照您想要的顺序调用测试函数。这是最简单的方法,唯一的缺点是第一个失败的测试函数将阻止任何剩余的测试函数执行

根据您对情况的描述,这是我建议您使用的解决方案

如果粗体部分对您来说是个问题,那么您可以通过利用内置的数据驱动测试功能来完成隔离测试的有序执行。它更复杂,感觉有点脏,但它完成了任务

简而言之,您可以定义一个数据源(如CSV文件或数据库表),该数据源控制运行测试的顺序以及实际包含测试功能的函数的名称。然后将该数据源挂接到数据驱动测试中,使用顺序读取选项,并以所需的顺序执行函数,作为单独的测试

[TestClass]
public class OrderedTests
{
    public TestContext TestContext { get; set; }

    private const string _OrderedTestFilename = "TestList.csv";

    [TestMethod]
    [DeploymentItem(_OrderedTestFilename)]
    [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", _OrderedTestFilename, _OrderedTestFilename, DataAccessMethod.Sequential)]
    public void OrderedTests()
    {
        var methodName = (string)TestContext.DataRow[0];
        var method = GetType().GetMethod(methodName);
        method.Invoke(this, new object[] { });
    }

    public void Method_01()
    {
        Assert.IsTrue(true);
    }

    public void Method_02()
    {
        Assert.IsTrue(false);
    }

    public void Method_03()
    {
        Assert.IsTrue(true);
    }
}
在我的示例中,我有一个名为TestList.csv的支持文件,它被复制到输出。看起来是这样的:

TestName
Method_01
Method_02
Method_03
[TestMethod]
        public void AName1()
        {}
[TestMethod]
        public void BName2()
        {}
您的测试将按照您指定的顺序执行,并且处于正常的测试隔离状态(即,如果一个测试失败,其余的测试仍将执行,但共享静态类)


以上只是基本的想法,如果我在生产中使用它,我会在测试运行之前动态地生成测试函数名及其顺序。也许通过利用您找到的PriorityAttribute和一些简单的反射代码来提取类中的测试方法并对它们进行适当排序,然后将顺序写入数据源。

既然您已经提到了Visual Studio测试框架提供的有序测试功能,我将忽略这一点。您似乎还意识到,为了测试这个静态类而试图完成的工作是一个“坏主意”,所以我将忽略这一点

相反,让我们把重点放在如何确保您的测试按照您想要的顺序执行。一个选项(由@gaog提供)是“一个测试方法,多个测试函数”,在标记有
TestMethod
属性的单个函数中,按照您想要的顺序调用测试函数。这是最简单的方法,唯一的缺点是第一个失败的测试函数将阻止任何剩余的测试函数执行

根据您对情况的描述,这是我建议您使用的解决方案

如果粗体部分对您来说是个问题,那么您可以通过利用内置的数据驱动测试功能来完成隔离测试的有序执行。它更复杂,感觉有点脏,但它完成了任务

简而言之,您可以定义一个数据源(如CSV文件或数据库表),该数据源控制运行测试的顺序以及实际包含测试功能的函数的名称。然后将该数据源挂接到数据驱动测试中,使用顺序读取选项,并以所需的顺序执行函数,作为单独的测试

[TestClass]
public class OrderedTests
{
    public TestContext TestContext { get; set; }

    private const string _OrderedTestFilename = "TestList.csv";

    [TestMethod]
    [DeploymentItem(_OrderedTestFilename)]
    [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", _OrderedTestFilename, _OrderedTestFilename, DataAccessMethod.Sequential)]
    public void OrderedTests()
    {
        var methodName = (string)TestContext.DataRow[0];
        var method = GetType().GetMethod(methodName);
        method.Invoke(this, new object[] { });
    }

    public void Method_01()
    {
        Assert.IsTrue(true);
    }

    public void Method_02()
    {
        Assert.IsTrue(false);
    }

    public void Method_03()
    {
        Assert.IsTrue(true);
    }
}
在我的示例中,我有一个名为TestList.csv的支持文件,它被复制到输出。看起来是这样的:

TestName
Method_01
Method_02
Method_03
[TestMethod]
        public void AName1()
        {}
[TestMethod]
        public void BName2()
        {}
您的测试将按照您指定的顺序执行,并且处于正常的测试隔离状态(即,如果一个测试失败,其余的测试仍将执行,但共享静态类)

以上仅仅是基本的想法,如果我在生产中使用它,我将生成测试函数名及其名称
using NUnit.Framework;

namespace NUnit.Project
{
    public class ByOrder
    {
        public static bool Test1Called;
        public static bool Test2ACalled;
        public static bool Test2BCalled;
        public static bool Test3Called;

        [Test, Order(5)]
        public void Test1()
        {
            Test3Called = true;

            Assert.IsTrue(Test1Called);
            Assert.IsFalse(Test2ACalled);
            Assert.IsTrue(Test2BCalled);
        }

        [Test, Order(0)]
        public void Test2B()
        {
            Test2BCalled = true;

            Assert.IsTrue(Test1Called);
            Assert.IsFalse(Test2ACalled);
            Assert.IsFalse(Test3Called);
        }

        [Test]
        public void Test2A()
        {
            Test2ACalled = true;

            Assert.IsTrue(Test1Called);
            Assert.IsTrue(Test2BCalled);
            Assert.IsTrue(Test3Called);
        }

        [Test, Order(-5)]
        public void Test3()
        {
            Test1Called = true;

            Assert.IsFalse(Test2ACalled);
            Assert.IsFalse(Test2BCalled);
            Assert.IsFalse(Test3Called);
        }
    }
}