用behave(Python)定义场景的顺序(或必需场景)

9 投票
4 回答
9404 浏览
提问于 2025-04-18 18:07

我正在用behave来测试我的小Django应用。

我已经创建了一个叫做 user_management.feature 的文件,其中包含了这个场景:

Scenario: register
 Given I can access registration form
  When I put "doctor" in "username" field
   And I put "tardisBlue" in "password" field
   And I put "doctor@tardis.com" in "email" field
   And I press the "Register" button
  Then the registration is successful
   And I am logged in

一切运行得很好。

接下来我想开发的功能在文件 project_management.feature 中:

Scenario: create a project
  Given I am logged in
  When I go to the home page
   And I click on "Create new Project" link
   And I fill the fields
    | field | text           |
    | name  | Save Gallifrey |
   And I click on "Save" button
   And I go to the home page
  Then I see the project name in the project list

现在,当我执行测试时,behave会按字母顺序执行这些功能文件,所以 project_management.feature 会先被执行。

这会在第一个 given 处引发错误,因为用户还没有被创建。

我试着把第一个文件重命名为 01_user_management.feature,这样就能正常工作了。

你知道有没有更好的解决办法吗?

有没有什么配置文件可以让我指定功能文件的执行顺序?

或者我能否告诉系统某个场景需要先运行另一个场景?

4 个回答

2

来自@Andrew Johnson和jenisys的回答提供了三种指定步骤/场景/功能顺序的方法。在这里,我再补充几种方法:

  • 基本上和jenisys提到的列表文件是一样的,当你在命令行中指定功能文件时,功能会按照你写的顺序执行。虽然这似乎没有官方文档说明,但这是我观察到的情况。
  • 你还可以使用标签来控制命令行中运行哪些场景。比如用--tags=t1,t2,t3,这些场景会严格按照你写的顺序执行。非常方便。
2

使用 feature-listfiles,像这样:

behave @my_foo.featureset …

配合使用:

# -- FILE: my_foo.featureset
features/alice.feature
features/bob.feature:10
2

这件事似乎有两种方法可以解决。第一种是你可以使用Background来为多个场景设置初始状态。第二种是从其他步骤调用之前的步骤。第一种方法的示例大概是这样的:

Feature: logins
  Test login functionality

  Background: login
    Given I can access registration form
    And I put "doctor" in "username" field
    And I put "tardisBlue" in "password" field
    And I put "doctor@tardis.com" in "email" field
    And I press the "Register" button

  Scenario: successful login
    Then the registration is successful
    And I am logged in

  Scenario: create a project
    When I go to the home page
    And I click on "Create new Project" link
    And I fill the fields
     | field | text           |
     | name  | Save Gallifrey |
    And I click on "Save" button
    And I go to the home page
    Then I see the project name in the project list
5

你不应该让测试场景相互依赖。 这样做是完全可能的。我有多个大型复杂的测试套件,里面有上百个场景。我的每个场景都不依赖于之前运行的其他场景。

当你的测试套件很大,而其中有一个场景失败时,能够做到以下这一点是非常有用的:

behave -n 'failing scenario name'

这会让Behave只运行失败的场景。还有一个方法是使用 @wip 标签,它也能实现同样的效果。不过,如果你想测试的场景依赖于另一个场景,Behave就不会自动知道应该先运行那个场景。因此,你需要 a) 知道这种依赖关系,b) 手动选择所有你想运行的场景所依赖的场景。

在你的情况下(这也是我过去做过的),我会实现一个步骤 Given I am logged in as ...。我用正则表达式来实现它,这样我就可以使用

Given I am logged in as an administrator
Given I am logged in as a regular user
Given I am logged in as a user with permissions to delete articles

我正在测试的应用程序的数据库里预先加载了一些测试用户,这些用户对应于上面的案例。(还有一个测试是注册新用户,但这与预加载的用户是独立的。)这个 Given I am logged in as ... 步骤只是让用户登录,并不需要创建用户。

这样做的一个附带好处是,如果你在像Sauce Labs或BrowserStack这样的测试服务上运行你的测试套件,并使用Selenium,你可以实现 Given I am logged in as ... 步骤来节省大量测试时间。在这种情况下,每个Selenium命令都需要在你的Behave测试和在测试服务上运行的浏览器之间进行一次往返,这在互联网上可能需要相当长的时间。减少这种交互的次数可以大大缩短整个测试套件的运行时间。

撰写回答