扩展 xUnit.NET 以在处理类和定位测试方法时使用自定义代码

发布于 2024-07-12 07:49:17 字数 696 浏览 7 评论 0原文

我是 xUnit.NET 框架的忠实粉丝; 我发现它轻量、简单、干净且可扩展。

现在假设我有一个像这样的类:

public class AdditionSpecification
{
  static int result;

  public void Because()
  {
    result = 2 + 2;
  }

  public void Result_is_non_zero()
  {
    Assert.True(result <> 0);
  }

  public void Result_is_correct()
  {
    Assert.Equal(4, result);
  }
}

对于上面的测试类,我希望 xUnit.NET 查看 2 个测试用例并在每个测试用例之前运行because() 方法。

抛开您对我的类或方法名称、此测试/规范的结构、xUnit.NET 框架或 BDD 可能遇到的任何问题,这是我的问题:

我如何告诉 xUnit.NET 我想要自定义它如何识别并执行此类的测试方法而不在每个目标测试方法上使用自定义的类似[Fact]的属性?

我知道我可以从BeforeAfterAttribute派生来装饰每个测试执行前后具有自定义的方法。 我怎样才能在班级层面做到这一点? 我必须编写自定义跑步者吗?

I'm a big fan of the xUnit.NET framework; I find it light, simple, clean, and extensible.

Now let's say that I have a class like so:

public class AdditionSpecification
{
  static int result;

  public void Because()
  {
    result = 2 + 2;
  }

  public void Result_is_non_zero()
  {
    Assert.True(result <> 0);
  }

  public void Result_is_correct()
  {
    Assert.Equal(4, result);
  }
}

With the test class above I want xUnit.NET to see 2 test cases and to run the Because() method before each of them.

Leaving aside any issues you may have with my class or method names, the structure of this test/specification, the xUnit.NET framework, or BDD, here's my question:

How can I tell xUnit.NET that I want to customize how it identifies and executes test methods out of this class without using a custom [Fact]-like attribute on each target test method?

I know that I can derive from BeforeAfterAttribute to decorate each test method with custom before and after execution. How can i do this at the class level? Do i have to write a custom runner?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

生生漫 2024-07-19 07:49:17

xUnit.net 的 IUseFixture 允许您对每个夹具进行设置。 因此,您可以定义自己的固定装置类:

public class AdditionFixture : IDisposable
{
  public int Because() 
  {
    return 2 + 2;
  }

  public void Dispose()
  {
   //test tear down code
  }      
}

然后您的测试类可以实现它(需要实现 setFixture):

public class AdditionSpecification : IUseFixture<AdditionFixture>
{
  int result;

  public void SetFixture(AdditionFixture Fixture)
  {
   result = Fixture.Because();
  }

  [Fact]
  public void Result_is_non_zero()
  {
   Assert.True(result <> 0);
  }

  [Fact]
  public void Result_is_correct()
  {
   Assert.Equal(4, result);
  }
}

xUnit 运行程序将创建您的固定装置的单个实例,并在运行每个测试之前将其传递到 SetFixture。 运行所有测试后,如果夹具实现了 IDisposable,则运行器将处理该夹具。 我希望这有帮助!

codeplex 上的 xUnit wiki 有更多信息,包括如何实现 IUseFixture 来管理测试装置的数据库连接的一个很好的示例。

xUnit.net's IUseFixture allows you to do per fixture setup. You could therefore define your own fixture class:

public class AdditionFixture : IDisposable
{
  public int Because() 
  {
    return 2 + 2;
  }

  public void Dispose()
  {
   //test tear down code
  }      
}

Your test class can then implement this (with setFixture requiring implementing) :

public class AdditionSpecification : IUseFixture<AdditionFixture>
{
  int result;

  public void SetFixture(AdditionFixture Fixture)
  {
   result = Fixture.Because();
  }

  [Fact]
  public void Result_is_non_zero()
  {
   Assert.True(result <> 0);
  }

  [Fact]
  public void Result_is_correct()
  {
   Assert.Equal(4, result);
  }
}

The xUnit runner will create a single instance of your fixture, and pass it into SetFixture before running each test. After running all of your tests, the runner will then dispose of the fixture if it implements IDisposable. I hope that helps!

The xUnit wiki on codeplex has more information, including a nice example of how to implement IUseFixture to manage a database connection for you test fixtures.

℉服软 2024-07-19 07:49:17

所以事实证明我正在寻找 ITestClassCommand.EnumerateTestMethods() 方法。

  1. 默认的 xUnit.NET 测试运行器
    将迭代中的所有类
    您的测试组件。
  2. 对于每一个,它都会检查 RunWithAttribute;
    这是你重写的机会
    ITestClassCommand 实现
    用于识别方法
    包含测试。 (RunWithNUnit 是一个很好的例子)
  3. 调用 ITestClassCommand.EnumerateTestMethods() 来处理测试类并返回测试方法的 IEnumerable。
  4. 然后将每个测试 IMethodInfo 传递给 ITestClassCommand.EnumerateTestCommands(IMethodInfo testMethod) 以获取 ITestCommands 的 IEnumerable,
  5. 然后执行每个 ITestCommand 并有机会返回结果。

在上面的示例中,我需要类似的东西:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class RunWithMyTestClassCommandAttribute : RunWithAttribute
{
   public RunWithMyTestClassCommandAttribute()
               : base(typeof(MyTestClassCommand)) {}
}

然后我可以用以下内容装饰上面的示例:

[RunWithMyTestClassCommand]
public class AdditionSpecification
{
  static int result;

  public void Because()
  {
    result = 2 + 2;
  }

  public void Result_is_non_zero()
  {
    Assert.True(result <> 0);
  }

  public void Result_is_correct()
  {
    Assert.Equal(4, result);
  }
}

最后,在 MyTestClassCommand 中,我有机会在 EnumerateTestMethods() 和 EnumerateTestCommands(IMethodInfo testMethod) 之间使用我想要查找的任何逻辑并构造作为单独测试执行的 ITestCommand 实例。

顺便说一句,在研究这个问题的过程中,我在 xUnit.NET 框架中遇到了一个小错误,其中由 EnumerateTestMethods() 生成的自定义 IMethodInfo 从未出现在 EnumerateTestCommands(..) 中,因为它被测试解开并重新包装跑步者或其工厂之一。

我向 codeplex 上的 xUnit 项目提交了此问题,它是已于 2009 年 5 月 30 日 更正 xUnit.NET 1.5 CTP 2

So it turns out that I was looking for the ITestClassCommand.EnumerateTestMethods() method.

  1. The default xUnit.NET test runner
    will iterate over all the classes in
    your test assembly.
  2. For each one it will check for a RunWithAttribute;
    that's your chance to override the
    ITestClassCommand implementation
    that is used to identify methods
    containing tests. (RunWithNUnit is a good example)
  3. ITestClassCommand.EnumerateTestMethods() is called to process the test class and return an IEnumerable of test methods.
  4. each test IMethodInfo is then passed to ITestClassCommand.EnumerateTestCommands(IMethodInfo testMethod) to get the IEnumerable of ITestCommands
  5. each ITestCommand is then executed and given the opportunity to return a result.

In the case of my example above, I would need something like:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class RunWithMyTestClassCommandAttribute : RunWithAttribute
{
   public RunWithMyTestClassCommandAttribute()
               : base(typeof(MyTestClassCommand)) {}
}

Then I could decorate my above example with:

[RunWithMyTestClassCommand]
public class AdditionSpecification
{
  static int result;

  public void Because()
  {
    result = 2 + 2;
  }

  public void Result_is_non_zero()
  {
    Assert.True(result <> 0);
  }

  public void Result_is_correct()
  {
    Assert.Equal(4, result);
  }
}

Finally, in MyTestClassCommand, I get to opportunity between EnumerateTestMethods() and EnumerateTestCommands(IMethodInfo testMethod) to use whatever logic I want to locate and construct ITestCommand instances that get executed as individual tests.

BTW, in the process of researching this issue, I ran into a small bug in the xUnit.NET framework where a custom IMethodInfo generated by EnumerateTestMethods() never showed up in EnumerateTestCommands(..) because it was being unwrapped and rewrapped by the test runner or one of it's factories.

I submitted this issue to the xUnit project on codeplex and it was corrected on May 30th, 2009 for xUnit.NET 1.5 CTP 2

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文