[Cucumber] 如何寫出好的 Cucumber 測試

凌晨1:04

這週在網路上面讀到一篇 Write Great Cucumber Test, 看完挺有感觸的, 剛好自己這兩三個月都在用 Cucumber 寫 Acceptance Test. 趁這個機會就來做個 Summary 吧, 重點分成三個部分:

  • Feature file
  • Step Definitions file
  • Configuration



- 寫 Feature 檔

Feature 檔幫助非專業的 stackholders 使用並了解整個測試, 透過這份文件, 可以用協同合作的方式與測試人員及整個團隊搭起橋樑. 基於這個理由, 寫出一份好的 feature 檔無非是幫助整個團隊更有效率地使用 BDD 的方式來進行合作.

下面這些建議及標準, 可以幫助我們寫出好的 Cucumber feature 檔:
OrganizationFeature files can live at the root of the /features directory. However, features can be grouped in a subfolder if they describe a common object. The grouped filenames should represent the action and context that is covered within.
Feature FilesEvery *.feature file consists in a single feature, focused on the business value.
Gherkin TemplateFeature: Title (one line describing the story)

Narrative Description: As a [role], I want [feature], so that I [benefit]

Scenario: Title (acceptance criteria of user story)
Given [context]
And [some more context]...
When [event]
Then [outcome]
And [another outcome]...

Scenario: ...
BackgroundThe background needs to be used wisely. If you use the same steps at the beginning of all scenarios of a feature, put them into the feature’s background scenario. The background steps are run before each scenario.
ScenariosKeep each scenario independent. The scenarios should run independently, without any dependencies on other scenarios.
Scenario OutlineIf you identify the need to use a scenario outline, take a step back and ask the following question: Is it necessary to repeat this scenario ‘x’ amount of times just to exercise the different combination of data? In most cases, one time is enough for UI level testing.
Write Declarative Scenarios, Not ImperativeThe declarative style describes behavior at a higher level, which I think improves the readability of the feature by abstracting out the implementation details of the application.

Example: Imperative

Scenario: User logs in

  Given I am on the homepage

  When I click on the "Login" button

   And I fill in the "Email" field with "me@example.com"

   And I fill in the "Password" field with "secret"

   And I click on "Submit"

  Then I should see "Welcome to the app, John Doe"


Example: Declarative

Scenario: User logs in

  Given I am on the homepage

  When I log in

  Then I should see a login notification


Just avoid unnecessary details in your scenarios.
Given, When, and Then StatementsI’ve often seen people writing the Gherkin syntax confuse when to put the verification step in the Given, When, Then sequence. Each statement has a purpose.
  • Given is the pre-condition to put the system into a known state before the user starts interacting with the application

  • When describes the key action the user performs

  • Then is observing the expected outcome

Just remember the ‘then’ step is an acceptance criteria of the story.
TaggingSince tags on features are inherited by scenarios, please don’t be redundant by including the same tags on scenarios.

- 寫 Step Definitions

Cucumber 自己本身不可能知道你沒有定義過的步驟. 而 Step Definitions 就是將這些純文字翻譯成 Gherkin Steps, 作為與測試機器間的互動. 這些 Steps Definitions 會使用 Ruby 的語法來完成並且放在 features/step_definitions/*.steps.

這邊有一些建議及標準, 可以幫助我們寫出好的 Steps Definitions 檔:

Step DefinitionsKeep the step definitions unique. If your step definition names aren’t unique, then you will find during runtime the following exception is thrown - ambiguous match.
Hard-codingAs you know you shouldn't be hard coding parameters into your code. This applies to site URL’s as well to allow flexibility to globally change the value.
Reusable ObjectsAt the beginning of any automation project, you need to think about scalability and maintainability. A good programming practice is Don’t Repeat Yourself (or DRY) by creating reusable code. You will find many different ways to share code between Cucumber scenarios. Be careful!
  • Call other step definitions. Call step definitions from other step definitions by calling steps helper. (Avoid)

  • Use many_steps helper. It does everything that steps helper does, but gives you meaningful stack traces in case something goes wrong. (Avoid)

  • Use a Page Object Pattern should be mapped to a Ruby class file, and each method within the class represents a page object on the page. (Better Choice)

Why use the Page Object Pattern?

  • Readable DSL

  • Promotes reusable code

  • Centralizes UI coupling — one place to make changes rather than multiple places throughout step definitions
CodeNo sleep statements. It is better to use method or function with a built-in timeout.
RSpec ExpectationsThe rspec-expectations library is bundled with many built-in matchers for testing validation. Each of the matchers can be used with expect(..).to or expect(..).not_to to define positive and negative expectations respectively on an object under test. I recommend using rspec-expectations matchers over Selenium matchers for Ruby testing frameworks.

- Cucumber 的組態設定 


在 Ruby 使用 Cucumber 是一件很簡單的事情, 需包含下列這些組態檔案:

cucumber.ymlIt simplifies command-line execution by defining reusable profiles within the cucumber.yml file.
GemfileThe Gemfile is used to manage dependencies for a Ruby project. We should also pin the versions of these Ruby gems. If you don’t pin a Ruby version, it will auto update and break your automation.
RakefileRakefile is a software task management and build automation tool. It allows you to specify tasks and describe dependencies as well as group tasks in namespaces.
support/env.rbThe support/env.rb is an environment configuration file for Cucumber. This file is designed to provide flexibility by allowing you to do things easily, like toggle your execution environment from local to remote. To fully understand all the capabilities of this support file, you should take more time to read up on all of the capabilities.

心得

蠻喜歡文章最後提到的一段話


BDD (Cucumber) allows for team collaboration early in the planning and development phases. Keep the numbers down. Ask yourself and the team: “If I can write a low-level test for this user story, should I write an UI acceptance test?” We should automate only the things that need to be automated at the UI level. It is a known fact that low-level tests are more reliable compared to UI tests. Cucumber is code, and all types of programming require thoughts upfront before writing automated tests. It is so important to lay a test automation foundation that embraces coding standards and follows design patterns that everyone will follow during automation development.

其實 BDD 最大的精神就是協同合作 (collaboration), 而裡面有一個問題 “If I can write a low-level test for this user story, should I write an UI acceptance test?”

自己蠻認同他的答案, 也就是說我們應該只自動化在 UI 層級那些需要被自動化的部分, 因為這是一大家都知道的事實.

與其說 Cucumber 是 code 的一部份, 還不如說每當我們在寫自動化測試之前, 先制定 coding standard 和 遵循的設計模式 的方法, 讓這些方法成為自動化測試的基礎, 因此可以讓更多人投入來寫自動化測試.




[Reference]



You Might Also Like

0 意見