【问题标题】:"Run a method only if a condition is satisfied" pattern“仅在满足条件时运行方法”模式
【发布时间】:2018-05-04 14:59:48
【问题描述】:

我有办法

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

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

来自public class ATestClass。这个测试类运行两种类型的测试:

  • 需要在运行测试的机器上安装特定软件的测试
  • 可以免费运行的测试

为了处理这个问题,我添加了一个public class BaseTestClass,我从中派生了ATestClass,并在ATestClass 中添加了一个:

public bool isTheSoftwareInstalledOnTheMachine()
{
    // stuff
}

我从ATestClass“装饰”了所有内部测试范围,如下所示:

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

我觉得这太可怕了。我宁愿能够写出类似的东西:

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

但我不知道是否允许定义“自定义”[characterizer]'s。 (我什至不知道他们的正确词。)如果是,那会是最好的设计吗? (我听说过装饰器模式,但我不知道是否可以在我的上下文中使其足够通用,因为我可能需要将条件用于许多其他测试类。)无论如何,我将如何继续使用 @987654332 @的?

【问题讨论】:

  • 这叫做属性,你是否可以创建一个你的单元测试框架尊重的自定义属性取决于你使用的框架。
  • @CodeCaster thx,我添加了正确的标签,因为我知道了名称
  • @ujsgeyrr1f0d0d0r0h1h0j0j_juj 没有“the c# 单元测试框架”——但我猜你是在谈论 NUnit?
  • 不,那不是 NUnit。这就是 Visual Studio 附带的框架。

标签: c# attributes decorator


【解决方案1】:

我知道你正在使用 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);
        }
    }
}

【讨论】:

    【解决方案2】:

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

    但我想您甚至不需要属性来执行此操作。您可以通过将逻辑放在测试方法中来简单地忽略测试:

    [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() { /* ... */ }
    

    编辑:您还可以将TestCaseAttribute 与特定方法一起使用,该方法在满足条件时返回TestCase

    [TestCaseSource("ProvideTestcases")]
    public void MyTest() { /* ... */ }
    
    private static IEnumerable<TestCaseData> ProvideTestcases()
    {
        if(RunIfTheSoftwareInstalledOnTheMachine)
            yield return new TestCaseData();
    }
    

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

    【讨论】:

    • 这就是我已经在做的事情,而且我提到发现可怕......?
    • @ujsgeyrr1f0d0d0r0h1h0j0j_juj IMO 与使用属性相比,它的可读性或多或少 - 这就是你应该始终争取的目标。
    • 如果我确实想使用我在问题中所写的属性怎么办?
    • 您只能使用CategoryAttribute。没有办法让你的测试框架解释你自己的属性应该是什么意思。
    • 为什么?我的意思是,如果我以某种方式在某处定义了这个新属性(这是我的问题的一部分),并且如果它的名称与NUnit 的属性不冲突,为什么NUnit 不能正确解释它?...顺便说一句,我没有使用NUnit,我使用的是visual studio测试框架,问题已更新
    【解决方案3】:

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

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

    【讨论】:

    • 我不希望没有安装软件的用户(或更糟糕的是,构建机器)测试失败。
    • 这不回答我的问题
    【解决方案4】:

    对于 Nunit 2.6,HimBromBeere 的答案略有不同,对我来说效果很好。测试用例显示为忽略。

    [TestCaseSource("ProvideTestcases")]
    public void MyTest() { /* ... */ }
    
    private static IEnumerable<TestCaseData> ProvideTestcases()
    {
        if(RunIfTheSoftwareInstalledOnTheMachine)
            yield return new TestCaseData().Ignore();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      • 2017-12-12
      • 2013-01-11
      相关资源
      最近更新 更多