Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.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# &引用;仅当满足条件时才运行方法;图案_C#_Attributes_Decorator - Fatal编程技术网

C# &引用;仅当满足条件时才运行方法;图案

C# &引用;仅当满足条件时才运行方法;图案,c#,attributes,decorator,C#,Attributes,Decorator,我有办法 using Microsoft.VisualStudio.TestTools.UnitTesting; // using visual studio's test framework [TestMethod] public void ATestMethod() { // stuff } 从一个公共类ATestClass。此测试类运行两种类型的测试: 要求在运行测试的机器上安装特定软件的测试 可以免费运行的测试 为了处理这个问题,我添加了一个公共类BaseTestClas

我有办法

using Microsoft.VisualStudio.TestTools.UnitTesting; // using visual studio's test framework

[TestMethod]
public void ATestMethod()
{
    // stuff
}
从一个
公共类ATestClass
。此测试类运行两种类型的测试:

  • 要求在运行测试的机器上安装特定软件的测试
  • 可以免费运行的测试
为了处理这个问题,我添加了一个
公共类BaseTestClass
,我从中派生了
ATestClass
,并在
ATestClass
中添加了一个:

public bool isTheSoftwareInstalledOnTheMachine()
{
    // stuff
}
我“修饰”了
ATestClass
中所有内部测试范围,如下所示:

[TestMethod]
public void ATestMethod()
{
    if (isTheSoftwareInstalledOnTheMachine())
    {
        // stuff
    }
}
我觉得这很可怕。我更希望能够写出以下内容:

[TestMethod]
[RunIfTheSoftwareInstalledOnTheMachine]
public void ATestMethod()
{
    // stuff
}

但我不知道是否允许定义“自定义”
[characterizer]
。(我甚至不知道用什么词来形容它们。)如果是,那是最好的设计吗?(我听说过decorator模式,但我不知道在我的上下文中它是否足够通用,因为我可能需要将该条件用于许多其他测试类。)无论如何,我将如何继续使用
角色化器?

如果您定义自己的属性,您肯定必须自己检查它的存在性。您不能期望您的框架猜测属性的用途

但我想你甚至不需要一个属性来做这件事。您可以通过将逻辑放在测试方法中忽略测试:

[Test]
public void MyTest()
{
    if(!RunIfTheSoftwareInstalledOnTheMachine)
        Assert.Ignore("Test not run because no software was installed");
    // your actual test-code
}
另一种方法是使用NUnit提供的
CategoryAttribute
,使用它,您只能运行属于所提供类别的测试:

[Test]
[Category("SoftwareInstalled")]
public void MyTest() { /* ... */ }
编辑:您还可以将
TestCase属性
与特定方法一起使用,该方法在满足条件时返回
TestCase

[TestCaseSource("ProvideTestcases")]
public void MyTest() { /* ... */ }

private static IEnumerable<TestCaseData> ProvideTestcases()
{
    if(RunIfTheSoftwareInstalledOnTheMachine)
        yield return new TestCaseData();
}
[TestCaseSource(“ProvideTestcases”)]
public void MyTest(){/*…*/}
私有静态IEnumerable ProvideTestcases()
{
如果(运行安装在机器上的软件)
返回新的TestCaseData();
}

如果不满足条件,则根本不会生成测试用例。

如果定义自己的属性,则必须自己检查其存在性。您不能期望您的框架猜测属性的用途

但我想你甚至不需要一个属性来做这件事。您可以通过将逻辑放在测试方法中忽略测试:

[Test]
public void MyTest()
{
    if(!RunIfTheSoftwareInstalledOnTheMachine)
        Assert.Ignore("Test not run because no software was installed");
    // your actual test-code
}
另一种方法是使用NUnit提供的
CategoryAttribute
,使用它,您只能运行属于所提供类别的测试:

[Test]
[Category("SoftwareInstalled")]
public void MyTest() { /* ... */ }
编辑:您还可以将
TestCase属性
与特定方法一起使用,该方法在满足条件时返回
TestCase

[TestCaseSource("ProvideTestcases")]
public void MyTest() { /* ... */ }

private static IEnumerable<TestCaseData> ProvideTestcases()
{
    if(RunIfTheSoftwareInstalledOnTheMachine)
        yield return new TestCaseData();
}
[TestCaseSource(“ProvideTestcases”)]
public void MyTest(){/*…*/}
私有静态IEnumerable ProvideTestcases()
{
如果(运行安装在机器上的软件)
返回新的TestCaseData();
}

如果不满足条件,则根本不会生成测试用例。

如果机器上安装的软件要求通过任何测试,并且任何一个测试失败都意味着整个套件失败,那么如果安装了软件,为什么还要麻烦检查多个测试呢?如果没有安装软件,只需编写一个失败的测试,并抛出一个有用的异常。比如:

[Test]
public void EnsureImportantSoftwareIsInstalled()
{
    if(!importantSoftwareIsInstalled)
    {
         Assert.Fail($"Software X must be installed for the tests in {nameof(MyTestClass)} to run, please install it");
    }
}

如果机器上安装的软件要求通过任何测试,并且任何一个测试失败都意味着整个套件失败,那么如果安装了软件,为什么还要麻烦检查多个测试呢?如果没有安装软件,只需编写一个失败的测试,并抛出一个有用的异常。比如:

[Test]
public void EnsureImportantSoftwareIsInstalled()
{
    if(!importantSoftwareIsInstalled)
    {
         Assert.Fail($"Software X must be installed for the tests in {nameof(MyTestClass)} to run, please install it");
    }
}

我知道您正在使用VS测试框架,但如果您可以更改为NUnit,您可以实现您想要的

测试用例:

using NUnit.Framework;

[TestFixture]
public class MyAppTests
{
    [Test]
    [RunIfTheSoftwareInstalledOnTheMachine]
    public void ATestMethod()
    {
        // Executes if custom attribute is true, otherwise test case is ignored
    }
}
using NUnit.Framework;
using NUnit.Framework.Interfaces;

public class TestHelper
{
    public static bool IsTheSoftwareInstalledOnTheMachine()
    {
        // Return state of software
        return true;
    }
}

public class RunIfTheSoftwareInstalledOnTheMachineAttribute : Attribute, ITestAction
{
    public ActionTargets Targets { get; private set; }

    public void AfterTest(ITest test) {}

    public void BeforeTest(ITest test)
    {
        if (!TestHelper.IsTheSoftwareInstalledOnTheMachine())
        {
            Assert.Ignore("Omitting {0}. Software is not installed on machine.", test.Name);
        }
    }
}
自定义属性:

using NUnit.Framework;

[TestFixture]
public class MyAppTests
{
    [Test]
    [RunIfTheSoftwareInstalledOnTheMachine]
    public void ATestMethod()
    {
        // Executes if custom attribute is true, otherwise test case is ignored
    }
}
using NUnit.Framework;
using NUnit.Framework.Interfaces;

public class TestHelper
{
    public static bool IsTheSoftwareInstalledOnTheMachine()
    {
        // Return state of software
        return true;
    }
}

public class RunIfTheSoftwareInstalledOnTheMachineAttribute : Attribute, ITestAction
{
    public ActionTargets Targets { get; private set; }

    public void AfterTest(ITest test) {}

    public void BeforeTest(ITest test)
    {
        if (!TestHelper.IsTheSoftwareInstalledOnTheMachine())
        {
            Assert.Ignore("Omitting {0}. Software is not installed on machine.", test.Name);
        }
    }
}

我知道您正在使用VS测试框架,但如果您可以更改为NUnit,您可以实现您想要的

测试用例:

using NUnit.Framework;

[TestFixture]
public class MyAppTests
{
    [Test]
    [RunIfTheSoftwareInstalledOnTheMachine]
    public void ATestMethod()
    {
        // Executes if custom attribute is true, otherwise test case is ignored
    }
}
using NUnit.Framework;
using NUnit.Framework.Interfaces;

public class TestHelper
{
    public static bool IsTheSoftwareInstalledOnTheMachine()
    {
        // Return state of software
        return true;
    }
}

public class RunIfTheSoftwareInstalledOnTheMachineAttribute : Attribute, ITestAction
{
    public ActionTargets Targets { get; private set; }

    public void AfterTest(ITest test) {}

    public void BeforeTest(ITest test)
    {
        if (!TestHelper.IsTheSoftwareInstalledOnTheMachine())
        {
            Assert.Ignore("Omitting {0}. Software is not installed on machine.", test.Name);
        }
    }
}
自定义属性:

using NUnit.Framework;

[TestFixture]
public class MyAppTests
{
    [Test]
    [RunIfTheSoftwareInstalledOnTheMachine]
    public void ATestMethod()
    {
        // Executes if custom attribute is true, otherwise test case is ignored
    }
}
using NUnit.Framework;
using NUnit.Framework.Interfaces;

public class TestHelper
{
    public static bool IsTheSoftwareInstalledOnTheMachine()
    {
        // Return state of software
        return true;
    }
}

public class RunIfTheSoftwareInstalledOnTheMachineAttribute : Attribute, ITestAction
{
    public ActionTargets Targets { get; private set; }

    public void AfterTest(ITest test) {}

    public void BeforeTest(ITest test)
    {
        if (!TestHelper.IsTheSoftwareInstalledOnTheMachine())
        {
            Assert.Ignore("Omitting {0}. Software is not installed on machine.", test.Name);
        }
    }
}

对于Nunit 2.6,HimBromBeere的答案有一点变化,对我来说效果很好。测试用例显示为已忽略

[TestCaseSource("ProvideTestcases")]
public void MyTest() { /* ... */ }

private static IEnumerable<TestCaseData> ProvideTestcases()
{
    if(RunIfTheSoftwareInstalledOnTheMachine)
        yield return new TestCaseData().Ignore();
}
[TestCaseSource(“ProvideTestcases”)]
public void MyTest(){/*…*/}
私有静态IEnumerable ProvideTestcases()
{
如果(运行安装在机器上的软件)
yield返回新的TestCaseData().Ignore();
}

对于Nunit 2.6,HimBromBeere的答案有一点变化,对我来说效果很好。测试用例显示为已忽略

[TestCaseSource("ProvideTestcases")]
public void MyTest() { /* ... */ }

private static IEnumerable<TestCaseData> ProvideTestcases()
{
    if(RunIfTheSoftwareInstalledOnTheMachine)
        yield return new TestCaseData().Ignore();
}
[TestCaseSource(“ProvideTestcases”)]
public void MyTest(){/*…*/}
私有静态IEnumerable ProvideTestcases()
{
如果(运行安装在机器上的软件)
yield返回新的TestCaseData().Ignore();
}

这称为属性,您是否可以创建一个受您的单元测试框架尊重的自定义属性取决于您使用的框架。@CodeCaster thx,我添加了正确的标记,因为我知道名称可能是helpful@ujsgeyrr1f0d0d0r0h1h0j0j_juj没有“c#单元测试框架”-但我猜你说的是努尼特?不,那不是努尼特。这就是Visual Studio附带的框架。这称为属性,您是否可以创建一个受单元测试框架尊重的自定义框架取决于您使用的框架。@CodeCaster thx,我添加了正确的标记,因为我知道名称可能是helpful@ujsgeyrr1f0d0d0r0h1h0j0j_juj没有“c#单元测试框架-但我猜你说的是努尼特?不,那不是努尼特。这就是VisualStudio附带的框架。不知何故,这就是我已经在做的事情,我提到了发现可怕@ujsgeyrr1f0d0d0r0h1h0j0j_juj在我看来,与使用属性相比,它的可读性并没有多少提高或降低,而这正是您应该努力做到的。如果我真的想使用我在问题中所写的属性,该怎么办?您只能使用
类别属性
。没有办法让您的testframework解释您自己的属性是什么