【问题标题】:NUnit TestFixture and TestCaseNUnit TestFixture 和 TestCase
【发布时间】:2020-01-02 11:31:03
【问题描述】:

我必须用 NUnit 编写一些集成测试来测试 HTTP 端点。 这意味着应该在所有测试方法之间共享 URL。

[TestFixture("http://my.endpoint.com")]
public class TestSuiteOne
{
   [TestCase(10, 20, Expected = 30)]
   [TestCase(20, 30, Expected = 50)]
   public int TestA(int a, int b, HttpResponseMessage sut)
   {
        // AAA.
   }

   [TestCase("XXX", "YYY", Expected = "ABC")]
   public int TestA(string a, string b, HttpResponseMessage sut)
   {
        // AAA.
   }
}

要获得来自测试套件属性的每个测试运行的 SUT 值,我知道两个选项:

选项 A(从类属性中读取 SUT)


public abstract class TestSuiteBase
{
    protected(string endpoint)
    {
        Sut = endpoint;
    }

    protected HttpResponseMessage Sut { get; }
}

[TestFixture("http://my.endpoint.com")]
public class TestSuiteOne : TestSuiteBase
{
   public TestSuiteOne(string endpoint) : base(endpoint)
   {
   }

   [TestCase(10, 20, Expected = 30)]
   [TestCase(20, 30, Expected = 50)]
   public int TestA(int a, int b)
   {
        // act (read content/response code/headers/etc); Making a call I do not consider as act.
        var actual = Sut.DoSomething();

        // assert
   }

   [TestCase("XXX", "YYY", Expected = "ABC")]
   public int TestA(string a, string b)
   {
        // act (read content/response code/headers/etc); Making a call I do not consider as act.
        var actual = Sut.DoSomething();

        // assert
   }
}

选项B(拦截测试方法调用)

public class MyTestCase: TestCaseAttribute
{
    public MyTestCase(params object[] args) : base(Resize(args))
    {
    }

    // I do resize before method call because VS Test Adapters discover tests to show a list in the test explorer
    private static object[] Resize(params object[] args)
    {
        Array.Resize(ref args, args.Length + 1);
        args[args.Length - 1] = "{response}";

        return args;
    }
}

public abstract class TestSuiteBase
{
   [SetUp]
   public void OnBeforeTestRun()
   {
       var ctx = TestContext.CurrentContext;

       var args = ctx.Test.Arguments;

       // Making a call I do not consider as act.
       args[args.Length - 1] = MakeCallAndGetHttpResponseMessage(args);
   }
}

[TestFixture("http://my.endpoint.com")]
public class TestSuiteOne : TestSuiteBase
{
   [MyTestCase(10, 20, Expected = 30)]
   [MyTestCase(20, 30, Expected = 50)]
   public int TestA(int a, int b, HttpResponseMessage sut)
   {
        // act (read content/response code/headers/etc); Making a call I do not consider as act.
        var actual = sut.DoSomething();

        // assert
   }

   [MyTestCase("XXX", "YYY", Expected = "ABC")]
   public int TestA(string a, string b, HttpResponseMessage sut)
   {
        // AAA.
   }
}

有没有更方便的方法可以将来自 TestFixture 的值与 TestCase 结合起来?

【问题讨论】:

  • 选项 1 看起来不错且可维护
  • 第一个选项看起来像“共享对象”;由于我试图避免的生命周期差异,只有对 xUnit 和 NUnit 有经验的人可能会感到困惑。 xUnit 每次测试运行都会创建一个类的实例,但 NUnit 的工作方式不同。那些只有 xUnit 经验的人,他们可能会按预期读取该属性,但同时 NUnit 人可能会将其读取为共享状态。如果测试并行运行,也无法使用该对象作为属性
  • 您创建每个夹具设置方法并在设置中初始化 sut
  • 不确定我理解你的意思,对不起,你能澄清一下吗?

标签: c# unit-testing testing nunit


【解决方案1】:

由于您将端点字符串放在TestFixtureAttribute 上,我将假设

  1. 您想与夹具中的所有测试用例共享它。
  2. 想与任何其他灯具共享它。

您的示例中唯一缺少的是一个构造函数,它将接受您提供的参数。只需添加类似...

public TestSuiteOne(string url)
{
     Sut = endpoint;
}

只要您将Sut 设为只读属性或字段,您的任何测试用例都无法更改它,无论它们是按顺序运行还是并行运行。

您提供的两个选项在我看来都过于复杂,至少在您解释问题的范围内。第一个最接近这个答案。

当然,您完全有可能对网站进行其他操作,这会导致并行(甚至顺序)测试相互干扰。不要那样做。 :-) 说真的,共享驱动程序与共享字符串完全不同,但这是一个不同的问题。

IMO,顺便说一下,您和您的团队应该习惯一个或另一个测试框架。您提到的生命周期问题并不是 NUnit 和 xUnit 之间唯一的细微差别!

【讨论】:

    猜你喜欢
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多