代码之家  ›  专栏  ›  技术社区  ›  Immortal Blue

分级“OneTimeSetup”方法

  •  1
  • Immortal Blue  · 技术社区  · 6 年前

    好的,我有一些nunit测试,我正在写这些测试来测试一个api。每当我需要运行这些测试时,我首先需要登录到API以获取令牌。首先,这就是我写OneTimeSetup的方式。

    因此,调用OneTimeSetup,我登录,共享字段存储令牌,每个测试都被称为API上的不同端点的测试。

    现在问题来了。我们已经决定要对响应中的各个字段进行单独的测试,这样我们就可以在出现错误时看到确切的情况(并且不会失败)。所以,我们将每个端点划分成它自己的测试。

    现在,OneTimeSetup被调用,它登录并调用端点,存储结果,所有测试都会启动,测试它们的小部分。

    问题是,登录需要时间,而且没有合理的理由说明所有单独的测试不能只使用相同的登录详细信息。是否有进一步细分测试/添加额外测试级别的方法?如果我们能得到这样的测试结果,那就太好了

    ApiTests <--- shared sign-in at this level - Endpoint 1 <--- call the endpoint at this level - Field 1 \ - Field 2 --- individual test results here - Field 3 / - Endpoint 2 <--- call the endpoint at this level - Field a \ - Field b --- individual test results here - Field c /

    2 回复  |  直到 6 年前
        1
  •  1
  •   Hermann.Gruber    6 年前

    您可以将测试类分组到相同的名称空间中,然后添加一个用setupfixture属性标记的附加类。这将在每个命名空间中只运行一次初始化代码。(不要与“testfixturesetup”属性混淆,该属性标记为自nunit v3以来已过时。谢谢查理的评论,我起初把它弄混了。)

    https://github.com/nunit/docs/wiki/SetUpFixture-Attribute

    代码示例(一如既往,您可以将每个类放在单独的代码文件中):

    using System.Diagnostics;
    using NUnit.Framework;
    
    namespace Test
    {
        [SetUpFixture]
        public class SharedActions
        {
            [OneTimeSetUp]
            public void SharedSignIn()
            {
                Debug.WriteLine("Signed in.");
            }
    
            [OneTimeTearDown]
            public void SharedSignOut()
            {
                Debug.WriteLine("Signed out.");
            }
        }
    
        [TestFixture]
        public class FirstEndpointTests
        {
            [Test]
            public void FirstEndpointTest()
            {
                Debug.WriteLine("Test for Endpoint A");
            }
        }
    
        [TestFixture]
        public class SecondEndpointTests
        {
            [Test]
            public void SecondEndpointTest()
            {
                Debug.WriteLine("Test for Endpoint B");
            }
        }
    }
    

    当您“调试所有”测试时,以下输出将显示在“调试”窗口中:

    已登录。 端点A测试 终点B试验 已注销。

        2
  •  0
  •   Adam G    6 年前

    这是实现这一目标的一种可能方法。

    如果您有一个公共的基类(从您的描述中听起来),您可以创建一个受保护的lazy来获取您的令牌,如下面的示例所示。

    public class ApiTestsBase
    {
        protected static Lazy<string> TokenLazy = new Lazy<string>(() =>
                                                                 {
                                                                     // Log in and get your API token
                                                                     Console.WriteLine("Logging into API to get token. You should only see this message on the first test that runs"); 
                                                                     return "DEADBEEF";
                                                                 });
    
    }
    
    [TestFixture]
    public class EndpointATests : ApiTestsBase
    {
        private string GetResultFromEndPoint()
        {
            // Call endpoint with token from TokenLazy.Value
            Console.WriteLine($"Calling EndpointA with token {TokenLazy.Value}");
            return "PayloadA";
        }
    
        [Test]
        public void Test1()
        {
            var payload = this.GetResultFromEndPoint();
            // Assert things about payload
        }
    
    }
    
    [TestFixture]
    public class EndpointBTests : ApiTestsBase
    {
        private string GetResultFromEndPoint()
        {
            // Call endpoint with token from TokenLazy.Value
            Console.WriteLine($"Calling EndpointB with token {TokenLazy.Value}");
            return "PayloadB";
        }
    
        [Test]
        public void Test1()
        {
            var payload = this.GetResultFromEndPoint();
            // Assert things about payload
        }
    
    }
    

    现在我使用的是字符串类型,但是您可以使用与您的情况相关的任何请求、响应和令牌类型。我怀疑您还可以创造性地将getResultFromEndpoint调用移动到基类,并使用抽象方法或属性来填充特定于端点的详细信息,但是您没有共享足够的代码让我尝试这样做。

    魔法在静态关键字中,这意味着每个应用程序域只能有一个实例。懒惰人只是将创建延迟到第一个引用。如果您的测试用例运行很长一段时间,它会变得更加复杂,因为您需要处理令牌续订,但是它仍然可以以类似的方式实现,使用一个singleton类,该类定期重新验证令牌年龄是否为>x。还可以使用singleton对象代替ST在上面的示例中,如果您没有设备的公共基类。