【问题标题】:Can I pass a deligate to a Xunit Theory我可以将代表传递给 Xunit 理论吗
【发布时间】:2020-11-04 11:44:11
【问题描述】:

我有兴趣在多个类上重用测试理论,特别是一些需要相同测试的构造函数。我最初的想法是使用委托来执行此功能。

但是,我认为我可能正在尝试重新发明轮子,尽管 C# 具有一些功能,但我认为我正在尝试一种不正确的方法。对于这种事情,是否有支持的方法使用比 InlineData 更正确的方法。

InlineData 似乎用于注入输入,因此我可能会测试给定测试的许多示例。但是我可以为几种方法提供几个变量并测试 ^x 而不是 *x

[Theory]
[InlineData(input => new ConcreteConstructor(input)) ]
public void Constructor_Should_Not_Throw_Expection (Action<string>)
{
  constructor("SomeString");            
}

N.B 我认为在这种情况下我应该使用Func 作为返回对象。无论如何,我怀疑这是完全错误的方法,所以这不是主要考虑因素。

【问题讨论】:

  • 您可以使用MemberData 机制将Func 作为测试参数传递(您不能使用属性制作Func,因此它永远不会与InlineData 一起使用
  • 谢谢@RubenBartelink 我会试试 MemberData
  • 我觉得这里不能用Func,因为不同的构造函数会返回不同的类型。因此,只有当所有类型都具有相同的基类时才有可能。然后至少你可以转换到那个基类并检查一些基本的东西。
  • 同意@yevheniy-tymchishin。无论如何,我们都不需要返回任何东西,就像寻找异常而不是结果一样。

标签: xunit.net


【解决方案1】:
public static IEnumerable<object[]> TestData()
{
  Action<string> a1 = input => new ConcreteConstructor(input);
  yield return new object[] { a1 };
  Action<string> a2 = input => new AnotherConstructor(input);
  yield return new object[] { a2 };
}

[Theory]
[MemberData(nameof(TestData))]
public void Constructor_Should_Not_Throw_Expection(Action<string> constructor)
{
  constructor("SomeString");
}

【讨论】:

  • 这肯定是标题的答案。我对此进行了一些讨论 => 我应该重用这样的代码吗?我认为在可能的情况下我会使用抽象基类,但在某些情况下传递委托是正确的方法。多态性与组合。我喜欢继承方法的一个原因是我为我的测试取了好听的名字,而且可以说它更容易阅读。
  • 我认为这里没有正确的答案——你必须决定:委托还是继承。
【解决方案2】:

感谢Yevheniy Tymchishin 他的answer,我想添加其他方法,以防万一有人想添加 delagate 而不在 yield return 之外声明新对象。

static IEnumerable<object[]> Data
{
    get 
    {
        //Yevheniy's approach
        Action<string> a1 = input => Construct(input);
        yield return new object[] { a1 };

        //new approach with hidden parameter
        yield return new object[] {new Action<string> (Construct)};
        
        //same but with exposed parameter syntax
        yield return new object[] {new Action<string> ((input) => Construct(input))};
    }
}

它们三个都做完全相同的事情,只是语法不同,相同的逻辑适用于任何其他委托类型(func 或其他)

【讨论】:

    【解决方案3】:

    一种继承通用抽象类的解决方案:

    abstract public class CommonTest_ConstructorShould
    {   
            public abstract void Constructor(string input);
    
            [Fact]
            public void Constructor_Should_Not_Throw_Expection()
            {
                Constructor(System.IO.Directory.GetCurrentDirectory());
            }
    
            [Fact]
            public void Constructor_Should_Throw_Exception()
            {
                Assert.Throws<ArgumentException>(() => Constructor("/PPPPPPPPPPPPPPPPPPPPPPP"));
            }
        }
    
        public class LunarCalendarClient_ConstructorShould : LocalJsonClient_ConstructorShould
        {   
            override public void Constructor(string input){
                new ConcreteClass(input);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-11
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      • 2017-10-09
      相关资源
      最近更新 更多