Sử dụng lại các bước Dưa chuột


103

Tôi muốn sử dụng lại một số bước Cucumber nhưng dường như không thể tìm thấy cách phù hợp.

Tôi muốn viết một bước như sau:

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end

Nhưng sau đó có một bước khác như:

Given /^I login successfully$
  # call "Given I login with valid credentials"
end

Vì vậy, trong thử nghiệm xác thực người dùng, tôi có thể sử dụng cái trước, nhưng hầu hết những nơi khác, tôi có thể sử dụng cái sau và không thực sự phải mã lại.

Có cách nào để gọi bước khác đó không, hay tôi chỉ đặt logic trong một phương thức trợ giúp và gọi phương thức đã nói từ mỗi tác vụ (về cơ bản là tái cấu trúc trích xuất phương thức, sau khi đọc câu hỏi của tôi, tôi tin rằng đó thực sự là cách tốt nhất dù sao)?


1
Trong trường hợp có ai đó nhầm lẫn, mọi người ở đây bỏ qua doyêu cầu bắt đầu do...endkhối trong định nghĩa bước Ruby. Trong thực tế, nó được yêu cầu.
Shaun Lebron

Câu trả lời:


102

CẬP NHẬT : Phương pháp được mô tả bên dưới không được dùng nữa. Cách đề xuất để gọi một bước từ trong một bước khác bây giờ trông giống như sau:

Given /^I login successfully$/
    step "I login with valid credentials" 
end 

Phương thức cũ, không dùng nữa (để tham khảo):

Bạn có thể gọi các bước từ các bước khác như sau:

Given /^I login successfully$/
  Given "I login with valid credentials"
  Then "I should be logged in"
end

Nếu tất cả các tình huống trong một tính năng yêu cầu bước này (hoặc các bước khác), bạn cũng có thể thêm Nền cho từng tính năng, với các bước phổ biến, như sau:

Background:
  Given I log in with valid credentials

Scenario: Change my password
  Given I am on the account page

5
Thậm chí dễ dàng hơn là dán mã dưa chuột ở như vậy:steps %Q{Given I am logged in}
BrendanDean

1
@BrendanDean Khi câu trả lời này được chấp nhận, stepsphương pháp này không tồn tại. Xem câu trả lời của tôi dưới đây.
michaeltwofish

Xin lưu ý rằng các bước kết hợp hiện được coi là một mô hình chống lại và nên tránh. Xem wiki Dưa chuột - Cucumber.io/docs/guides/anti-patterns/…
Jan Molak

103

Lưu ý rằng phương thức gọi các bước trong các bước đã thay đổi trong các phiên bản gần đây của dưa chuột, bạn sẽ thấy nếu gặp lỗi như "CẢNH BÁO: Việc sử dụng 'Cho / Khi / Thì' trong định nghĩa bước không được dùng nữa, hãy sử dụng 'bước' để thay vào đó gọi các bước khác: /path/to/step_definitions/foo_steps.rb: 631: in `block in '". Xem wiki dưa chuột để biết chi tiết.

Ý chính của thay đổi là bây giờ bạn nên sử dụng các phương thức stephoặc steps.

When /^I make all my stuff shiny$/
  step "I polish my first thing"
end

When /^I make all my stuff shiny$/
  steps %Q{
    When I polish my first thing
    When I shine my second thing
  }
end

18
Đối với những gì nó đáng giá, sau nhiều thời gian với Cucumber, tôi khuyên bạn không nên sử dụng các bước trong các bước. Các vấn đề khó theo dõi và nó thực sự làm cho việc bảo trì khó hơn. Thay vào đó, hãy sử dụng các phương pháp trợ giúp.
michaeltwofish

2
Có thể, bạn nên đưa nhận xét này vào câu trả lời của mình vì nó được ủng hộ rất nhiều và vẫn nhận được phiếu bầu. Nó sẽ giúp mọi người chú ý thông tin này
Andrei Botalov

chào @michaeltwofish, có gì thay đổi trong năm 2017 không? Tôi nhận được syntax error, unexpected tIDENTIFIER, expecting keyword_end stackoverflow.com/questions/43319331/…
ericn

43

Gọi các bước từ định nghĩa bước là một cách thực hành không tốt và có một số nhược điểm :

  1. Nếu kịch bản không thành công và có các lệnh gọi bước lồng nhau, bạn sẽ chỉ nhận được định nghĩa bước được gọi cuối cùng trong dấu vết ngăn xếp. Có thể khó tìm từ nơi mà bước cuối cùng được gọi là
  2. Lời gọi đến stepdef đôi khi khó tìm và khó đọc hơn phương thức ruby
  3. Các phương thức Ruby cung cấp cho bạn nhiều sức mạnh hơn là gọi các bước từ bước định nghĩa

Aslak Hellesøy khuyên bạn nên trích xuất các hành động phổ biến cho Thế giới thay vì sử dụng lại các bước. Nó cô lập những hành động đó ở một nơi, làm cho mã này dễ tìm hơn. Bạn cũng có thể trích xuất mã vào các lớp hoặc mô-đun Ruby thông thường.

#/support/world_extensions.rb
module KnowsUser
  def login
    visit('/login')
    fill_in('User name', with: user.name)
    fill_in('Password', with: user.password)
    click_button('Log in')
  end

  def user
    @user ||= User.create!(:name => 'Aslak', :password => 'xyz')
  end
end
World(KnowsUser)

#/step_definitions/authentication_steps.rb
When /^I login$/ do
  login
end

Given /^a logged in user$/ do
  login
end

Đây là một cuộc thảo luận hữu ích về chủ đề này trong danh sách gửi thư của Cucumber - liên kết


2
Tôi tin rằng cách tiếp cận này tốt hơn nhiều so với việc gọi các hàm step hoặc các bước vì những lý do tương tự đã đề cập ở trên.
pisaruk

2
Điều này có một lợi ích khác. Sử dụng Idea (hoặc Rubymine), bạn có thể dễ dàng chuyển đến định nghĩa hàm, nhưng không phải đến các bước trong bước% {...}.
slipset

cũng như thiết lập này tuân theo nguyên tắc KHÔ
Sorcerer86pt

2
Mặc dù tôi đã gặp phải vấn đề về việc sử dụng lại các bước, nhưng tôi nghĩ điều này thật tệ. Đăng nhập chỉ là tổng hợp của các bước khác nhau: "thăm một cái gì đó", "điền một cái gì đó". Cách tự nhiên sẽ là sử dụng lại các bước, thay vì chuyển đổi từng bước thành một lệnh gọi đến một hàm. IMO, các bước gọi bên trong các bước chỉ nên được cải thiện.
dgmora

9

Tốt nhất hãy gói các bước của bạn trong% {} thay vì dấu ngoặc kép. Sau đó, bạn không cần phải thoát khỏi dấu ngoặc kép mà bạn sẽ cần sử dụng thường xuyên.:

Given /^I login successfully$
  step %{I login with valid credentials}
end

Given /^I login with (.*) credentials$/ |type|
  # do stuff with type being one of "invalid" or "valid"
end

5
Đây nên là một bình luận thay vì một câu trả lời.
Kelvin

1

Sử dụng lại các từ khóa trong tệp tính năng sẽ cung cấp khả năng tái sử dụng mã.

Chúng tôi thực sự KHÔNG khuyến khích gọi độ lệch bước trong độ phân giải bước.

Tôi sẽ viết tệp tính năng của mình theo cách này,

Scenario Outline: To check login functionality
    Given I login with "<username>" and "<password>"
    Then I "<may or may not>" login successfully

Examples:
    |username|password|may or may not|
    |paul    |123$    |may           |
    |dave    |1111    |may not       |

Trong định nghĩa bước của tôi, (Đây là Java)

@Given(I login with \"([^\"]*)\" and \"([^\"]*)\"$)
public void I_login_with_and(String username, String password){

   //login with username and password

}

@Then(I \"([^\"]*)\" login successfully$)
public void I_login_successully_if(String validity){

    if(validity.equals("may")){
        //assert for valid login
    }
    else
    if(validity.equals("may not")){
        //assert for invalid login
    }
}

Bằng cách này, có rất nhiều khả năng tái sử dụng mã. Cùng với Given và Then của bạn xử lý cả các kịch bản hợp lệ và không hợp lệ. Đồng thời, tệp tính năng của bạn có ý nghĩa đối với người đọc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.