【问题标题】:How to write specflow scenarios that follow each other and share data?如何编写相互跟随并共享数据的specflow场景?
【发布时间】:2018-02-03 02:02:24
【问题描述】:

TLDR - 编写相互跟随并共享数据的 specFlow 场景的最佳方式是什么?例如场景 A - 创建一个用户,然后场景 B 使用该用户登录(登录需要在创建用户场景中指定的用户名和密码)。

大家好,

在尝试找出在网站上为典型的注册用户表单编写场景的最佳方法,然后是测试登录的场景时,我让自己陷入了困境。

我尝试创建一个单独的类的实例来存储我的注册表单的所有详细信息,当它到达这一步时(认为这是上下文注入)。例如

[Binding]
public class AdmissionsPortalFeaturesSteps : BaseStep
{
    private UserDetails userDetails;

我遇到的问题是以下场景需要在前一个场景中生成的密码,而我无法通过类似...的方式访问它

userDetails.Password 

这是我目前无法使用的,因为我想将密码值从第一个场景传递到第二个场景......(请注意,如果该字段设置为“随机”,则会在我的c#代码)

Scenario: Create a new user via the Admissions Portal
    Given I will navigate to the Admissions Portal login page
    When I click the Create an Account link
    Then I will be on the ontrack: prospect - Register page
    Given I have entered the following values on the registration page
    | fieldName                  | value  |
    | Title                      | random |
    | Firstname                  | random |
    | Middlename                 | random |
    | Surname                    | random |
    | DOB                        | random |
    | Gender                     | random |
    | EmailAddress               | random |
    | MobileNumber               | 0      |
    | Password                   | random |
    | SecurityQuestion           | random |
    | SecurityAnswer             | random |
    And I click on the Register button
    Then I will be on the Login page
        And I will get a popup confirming my registration details
    Then I close the browser window

Scenario: I am able to login to the Admissions Portal with a newly created user
    Given I will navigate to the Admissions Portal login page
        And I enter a username and password and click to login
    Then I will be on the ontrack: prospect - Home page
    Then I close the browser window

目前我看到我有以下选项

  1. 扩展第一个场景以包括登录以及使用上下文注入在步骤之间共享数据。
  2. 在我的登录步骤中重复包含表格的注册步骤。
  3. 编写一个新的更短的步骤,在没有表格的情况下生成我的用户,并在两种情况下都使用它(我可能想稍后指定具有在表单中设置的特定值的场景,但我承认我最好放弃它)。李>

或者其他我没有想到的...

非常感谢,

【问题讨论】:

    标签: c# automated-tests specflow


    【解决方案1】:

    我尝试确保我的 specflow 场景不共享任何数据,以及是否可以在每次测试之间尽可能显式地重新生成整个数据库架构。

    这确保只有您在测试中安排的数据在数据库中

    因此,我将创建一个单独的 Given 步骤,该步骤要么贯穿创建帐户的所有步骤(您可以以编程方式调用这些步骤),要么具有一个单独的 Given 步骤,该步骤将所有为数据库播种的信息与您需要的信息短路.

    我还注意到您在测试中明确关闭了浏览器。我为启动/停止 Selenium 的 Web 创建了一个 BeforeScenario/AfterScenario 标签。这样您的测试只需要测试实际功能,而不是 Selenium 的启动/停止。

    public class SeleniumController
    {
        public static readonly SeleniumController Instance = new SeleniumController();
        public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(10);
    
        public IWebDriver Selenium { get; private set; }
    
        private void Trace(string message) { Console.WriteLine("-> {0}", message); }
    
        public void Start()
        {
            if (Selenium != null)
                return;
    
            string appUrl = ConfigurationManager.AppSettings["AppUrl"];
    
            var options = new ChromeOptions();
            options.AddArgument("test-type");
            Selenium = new ChromeDriver(options);
            Selenium.Manage().Timeouts().ImplicitlyWait(DefaultTimeout);
    
            Trace("Selenium started");
        }
    
        public void Stop()
        {
            if (Selenium == null) return;
    
            try
            {
                Selenium.Quit();
                Selenium.Dispose();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex, "Selenium stop error");
            }
            Selenium = null;
            Trace("Selenium stopped");
        }
    }
    

    场景标签

    public static class SeleniumSupport
    {
        private static bool ReuseWebSession
        {
            get { return ConfigurationManager.AppSettings["ReuseWebSession"] == "true"; }
        }
    
        [BeforeScenario("web")]
        public static void BeforeWebScenario()
        {
            SeleniumController.Instance.Start();
        }
    
        [AfterScenario("web")]
        public static void AfterWebScenario()
        {
            if (!ReuseWebSession)
                SeleniumController.Instance.Stop();
        }
    }
    

    抽象步骤基类访问 selenium webdriver

    public abstract class SeleniumStepsBase
    {
        protected IWebDriver Selenium { get { return SeleniumController.Instance.Selenium; } }
    }
    

    【讨论】:

    • 谢谢。是的,听起来是个好主意。需要进行一些整理,因此将在适当的地方添加之前和之后。
    【解决方案2】:

    您打算使用一种方案为另一种方案设置数据的意图是有缺陷的,并且注定要失败恕我直言。

    一个场景应该是完全独立的,并且能够独立运行,而不是依赖于另一个场景。 Specflow 是一个单元测试生成框架,但测试运行者可以决定运行测试的顺序。如果您有一个像您说想要的那样的依赖项,那么如果它们没有按顺序运行会发生什么?如果它们并行运行会发生什么?试图完成这项工作将逆流而上,不要这样做。

    而是让每个场景都自成一体。如果您有很多重复设置,请将其放在后台步骤中,或者创建一个调用所有其他步骤来进行设置的步骤,或者只创建一个仅执行您想要的设置的步骤,然后使用标准方法在步骤之间共享数据以管理您生成的密码等。

    【讨论】:

    • 谢谢山姆。对此进行了更多研究,您是完全正确的。我试图在一个场景中设置我的数据,然后在所有其他场景中使用该数据。正如您所指出的,如果测试无序运行,它们就会崩溃。我决定保留我的特定注册用户场景,然后有一个较短的版本“鉴于我已经创建了一个用户”,它调用了注册用户场景中的所有步骤。然后,我将其用作其他场景的设置。测试执行时间更长,因为我每次都创建一个用户,但测试现在完全独立。
    【解决方案3】:

    我使用 FeatureContext.Current 或 ScenarioContext.Current 来存储我在场景或功能之间传递的信息。 FeatureContext 是一个 Specflow 全局字典,可以在任何地方访问。 Specflow FeatureContext

    FeatureContext.Current["username"] = "someUsername";
    

    或者

    ScenarioContext.Current["username"] = "someUsername";
    

    【讨论】:

    • 我会避免这种共享数据的方法,因为如果不将上下文注入到您的步骤类中,它将无法在并行场景中工作,而且我认为它在未来的某个版本中将被弃用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多