Thử nghiệm khả năng hỗ trợ của chatGPT vào quy trình phát triển phần mềm hướng hành vi (BDD – Behavior Driven Development)
1. Giới thiệu
Quy trình phát triển phần mềm hướng hành vi (Behavior Driven Development – BDD) có nguồn gốc từ phương pháp phát triển định hướng kiểm thử (Test Driven Development – TDD), và được phát triển vào đầu những năm 2000 bởi Dan North, một nhà phát triển phần mềm. Sự ra đời của BDD được thúc đẩy bởi mong muốn khắc phục những khó khăn trong việc áp dụng TDD, đặc biệt là những vấn đề liên quan đến việc hiểu và viết các bài kiểm thử tự động.
a. TDD
TDD, được giới thiệu bởi Kent Beck, là một phương pháp phát triển phần mềm trong đó mã nguồn được viết thông qua việc viết các bài kiểm thử tự động trước. TDD nhấn mạnh việc viết mã kiểm thử cho một chức năng trước khi viết mã thực thi, sau đó sửa mã để đảm bảo bài kiểm thử thành công. Tuy nhiên, một trong những thách thức lớn của TDD là việc các nhà phát triển và các bên liên quan phi kỹ thuật (như quản lý dự án hay khách hàng) thường gặp khó khăn trong việc hiểu các bài kiểm thử, dẫn đến sự thiếu rõ ràng trong việc diễn đạt các yêu cầu.
b. BDD
Sự ra đời của BDD (2003): Dan North đã phát triển BDD như một cách tiếp cận nhằm làm cho TDD trở nên dễ hiểu hơn, cả về khía cạnh ngôn ngữ và quy trình. Thay vì chỉ tập trung vào kiểm thử, BDD tập trung vào việc mô tả hành vi mong muốn của hệ thống. Các bài kiểm thử trong BDD được viết dưới dạng các kịch bản dễ đọc, sử dụng ngôn ngữ tự nhiên có cấu trúc, ví dụ ngôn ngữ Gherkin (thường bằng tiếng Anh hoặc ngôn ngữ mà cả nhóm có thể hiểu).
c. Ngôn ngữ Gherkin và công cụ Cucumber
Gherkin là ngôn ngữ dùng để viết các kịch bản trong BDD, giúp mô tả hành vi của phần mềm một cách dễ hiểu. Gherkin sử dụng cấu trúc đơn giản và dễ đọc, thường bao gồm các từ khóa như Given, When, Then, And, và But để mô tả bối cảnh, hành động và kết quả mong đợi của một kịch bản.
Cucumber và các công cụ BDD khác: Để hỗ trợ BDD, nhiều công cụ đã được phát triển, trong đó nổi tiếng nhất là Cucumber. Cucumber cho phép viết các kịch bản kiểm thử theo định dạng ngôn ngữ Gherkin và tự động thực thi các kịch bản này. Ngôn ngữ Gherkin giúp cả kỹ thuật và phi kỹ thuật hiểu được yêu cầu, tạo điều kiện thuận lợi cho sự hợp tác trong nhóm.
Đặc điểm nổi bật của BDD:
- Ngôn ngữ dễ hiểu: Các kịch bản BDD được viết bằng ngôn ngữ tự nhiên, giúp mọi người trong nhóm, từ nhà phát triển đến khách hàng, đều có thể hiểu rõ yêu cầu.
- Liên kết chặt chẽ với yêu cầu kinh doanh: BDD giúp đảm bảo rằng các bài kiểm thử phản ánh đúng yêu cầu kinh doanh, và phần mềm được phát triển theo hướng giải quyết vấn đề thực tiễn.
- Sự hợp tác giữa các bên: BDD khuyến khích sự tham gia tích cực của tất cả các bên liên quan trong quá trình phát triển, bao gồm nhà phát triển, tester và các bên liên quan phi kỹ thuật.
BDD trở thành một phương pháp phát triển phổ biến, đặc biệt trong các dự án Agile, nhờ khả năng giúp cả nhóm phát triển và khách hàng giao tiếp hiệu quả hơn thông qua việc mô tả hành vi phần mềm rõ ràng.
2. Quy trình BDD
Quy trình BDD bao gồm 6 bước chính:
Bước 1: Xác định hành vi: Bắt đầu bằng việc xác định hành vi mà người dùng mong muốn (thông qua cuộc thảo luận với các bên liên quan).
Bước 2: Viết kịch bản kiểm thử: Viết các kịch bản kiểm thử dưới dạng ngôn ngữ tự nhiên có cấu trúc như là Gherkin (thường theo định dạng Given-When-Then) để tất cả cách thành viên bao gồm cả khách hàng có thể hiểu được.
Given: Trạng thái ban đầu.
When: Hành động được thực hiện.
Then: Kết quả mong đợi.
Bước 3: Chạy kiểm thử: Thực hiện các kịch bản để xác nhận rằng phần mềm hoạt động đúng với các yêu cầu.
Bước 4: Viết mã: Viết mã để thực hiện các hành vi đã được xác định.
Bước 5: Chạy lại kiểm thử: Kiểm tra lại tất cả các kịch bản để đảm bảo chúng thành công.
Bước 6: Tối ưu hóa mã: Cải thiện mã (refactor) trong khi duy trì tất cả các kịch bản kiểm thử thành công.
Trước đây, chúng ta phải làm thủ công hầu hết các bước trong quy trình trên, ngoại trừ bước 3 (chạy kiểm thử) và bước 5 (chạy lại kiểm thử) có công cụ Cucumber hỗ trợ thực hiện tự động. Ngoài ra, việc cài đặt các phần mềm cần thiết như Maven, JDK, Cucumber, vân vân và việc thiết lập các tham số phù hợp để thực thi được các kiểm thử với công cụ Cucumber cũng khá phức tạp.
3. Các bước thử nghiệm khả năng hỗ trợ của ChatGPT
Chúng tôi đã sử dụng ChatGPT vào quy trình phát triển một hệ thống Bank ATM đơn giản với đầu vào là bản mô tả yêu cầu dưới dạng user stories. Chúng tôi sử dụng một user story thể hiện một trong các yêu cầu chức năng của hệ thống để minh họa quy trình, đó là chức năng rút tiền từ tài khoản ATM.
Bước 1: Viết tất cả các kịch bản hành vi có thể có từ bản mô tả yêu cầu được viết dưới dạng user stories.
Chúng tôi đưa vào chatGPT như sau:
You are an expert business analyst with additional expertise in Software User Stories and BDD. You help turn business requirements given as User Stories into multiple BDD Given-When-Then scenarios.
A User Story is of the format: As a (user type) I want to (perform an action on the system) So that (I meet a desired outcome) A Given-When-Then scenario is of the format: Given (an initial context) When (an event occurs) Then (a testable outcome is satisfied) — I am writing a software as a Bank ATM. The user stories are: As a Bank ATM user, I want to withdraw money from the ATM So that I have money to use. Write BDD scenarios which meet the user story. |
Dưới đây là kết quả ChatGPT đã tạo tất cả các kịch bản hành vi có thể có dựa trên yêu cầu tôi đã đưa vào ChatGPT. Các kịch bản này được lưu trong tệp atm_withdrawal.feature.
Feature: ATM Transaction
Scenario: Customer withdraws cash successfully when balance is sufficient Given the customer has a balance of 1000000 And the ATM card is authenticated successfully When the customer requests to withdraw 500000 Then the ATM should dispense 500000 And the account balance should be 500000 Scenario: Customer fails to withdraw cash when balance is insufficient Given the customer has a balance of 200000 And the ATM card is authenticated successfully When the customer requests to withdraw 300000 Then an exception should be thrown |
Bước 2: ChatGPT tạo test cases và code cho hệ thống bank ATM theo các kịch bản hành vi ở trên.
Chúng tôi yêu cầu ChatGPT viết chương trình bằng ngôn ngữ Java, do đó các bước kiểm thử cũng như Test Driver (bộ điều khiển kiểm thử) cũng được tạo ra bằng ngôn ngữ Java. Dưới đây là những gì được đưa vào ChatGPT:
You are an expert java software developer. You know how to understand BDD scenarios of the form:
Scenario: scenario title Given (an initial context) When (an event occurs) Then (a testable outcome is satisfied) You know how to write tests first which can be executed by Cucumber. You have been asked to assist software developer to develop tests and code for a bank ATM system according to the given BDD specifications. |
Kết quả ChatGPT cung cấp một chương trình viết bằng ngôn ngữ Java chứa các bước kiểm thử được tích hợp như một Test Driver, một phiên bản của chương trình ATM viết bằng ngôn ngữ Java và một tệp cấu hình chứa thông tin cần cho Cucumber thực thi kiểm thử tự động.
- Tệp ATMTransactionSteps.java đóng vai trò như Test Driver để thực thi chương trình cần kiểm thử và so sánh với kết quả mong đợi, chúng tôi lưu tệp này ở nơi phù hợp trong thư mục dự án của Curcumber.
package com.bank.steps;
import atm.ATM; import io.cucumber.java.en.Given; import io.cucumber.java.en.When; import io.cucumber.java.en.Then; import static org.junit.Assert.*; public class ATMTransactionSteps { private ATM atm; private double withdrawalAmount; private double dispensedAmount; private String exceptionMessage; @Given(“the customer has a balance of {double}”) public void the_customer_has_a_balance_of(double initialBalance) { atm = new ATM(initialBalance); } @Given(“the ATM card is authenticated successfully”) public void the_ATM_card_is_authenticated_successfully() { // Logic for authenticating the ATM card, assuming it’s successful } @When(“the customer requests to withdraw {double}”) public void the_customer_requests_to_withdraw(double amount) { withdrawalAmount = amount; try { dispensedAmount = atm.withdraw(withdrawalAmount); } catch (IllegalArgumentException e) { exceptionMessage = e.getMessage(); } } @Then(“the ATM should dispense {double}”) public void the_ATM_should_dispense(double expectedDispenseAmount) { assertEquals(expectedDispenseAmount, dispensedAmount, 0.01); } @Then(“the account balance should be {double}”) public void the_account_balance_should_be(double expectedBalance) { assertEquals(expectedBalance, atm.getBalance(), 0.01); } @Then(“an exception should be thrown”) public void an_exception_should_be_thrown() { assertNotNull(exceptionMessage); assertEquals(“Số dư không đủ”, exceptionMessage); } } |
- Tệp mã nguồn của chương trình được lưu với tên tệp ATM.java
package atm;
public class ATM { private double balance; public ATM(double balance) { this.balance = balance; } public double withdraw(double amount) { if (balance >= amount) { balance -= amount; return amount; } else { // Sử dụng exception để xử lý lỗi, hoặc có thể xử lý cách khác throw new IllegalArgumentException(“Số dư không đủ”); } } public double getBalance() { return balance; } } |
- Tệp RunCucumberTest.java là tệp chứa thông tin nơi lưu đường dẫn cần thiết để Cucumber tìm tệp features và lớp chứa các bước cần kiểm thử
package com.bank;
import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions( features = “src/test/resources/features”, // Đường dẫn tới tệp feature glue = “com.bank.steps” // Đường dẫn tới các lớp chứa bước (steps) ) public class RunCucumberTest { } |
Cấu trúc thư mục của dự án phát triển hệ thống ATM theo quy trình BDD thực thi các bước kiểm thử bởi Cucumber như sau:
my-cucumber-project/
│
├── src/
│ ├── main/
│ │ └── java/
│ │ └── atm/
│ │ └── ATM.java
│ │
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── bank/
│ │ ├── ATMTransactionSteps.java
│ │ └── RunCucumberTest.java
│ │
│ └── resources/
│ └── features/
│ └── atm_withdrawal.feature
│
└── pom.xml
Với các kết quả mà ChatGPT mang lại như trên, chúng tôi đã có chương trình cần kiểm thử, các test cases, test driver đã được định nghĩa. Trước đó, chúng tôi đã cài đặt Cucumber, Maven, JDK là những phần mềm cần thiết để thực thi các dự án của Cucumber và chúng tôi cũng đã tạo một thư mục dự án Cucumber mới và đã thiết lập các tham số cấu hình cần thiết cho dự án. Tiếp theo, chúng tôi lưu các tệp mã nguồn mà ChatGPT cung cấp như được minh họa ở trên vào vị trí phù hợp trong thư mục dự án Cucumber để có thể tiến hành thực thi các test cases.
Bước 2: Thực thi các test cases bằng công cụ Cucumber
Trong bước này chúng ta chỉ cần ra lệnh cho Cucumber thực thi các test cases đã được lưu trong thư mục dự án và quan sát kết quả Cucumber hiển thị.
- Một số test cases không thực hiện được do có lỗi trong kịch bản kiểm thử, file features mà ChatGPT sinh ra. Chúng tôi đã gửi thông báo lỗi này cho ChatGPT để được hướng dẫn chỉnh sửa cho đến khi toàn bộ test cases được thực hiện tự động thành công bởi Cucumber.
- Một số test cases phát hiện lỗi chương trình. Chúng ta có thể gửi thông báo lỗi để ChatGPT tìm vị trí lỗi và hướng dẫn sửa lỗi.
4. Kết quả và đánh giá khả năng hỗ trợ của ChatGPT
ChatGPT có thể tự động hóa các bước sinh các kịch bản hành vi theo bản mô tả yêu cầu được mô tả theo form của user story. Sau đó ChatGPT sẽ sinh các bước kiểm thử và mã nguồn chương trình. Nếu chúng ta phát triển phần mềm theo quy trình BDD/TDD, ChatGPT có thể trợ giúp tất cả các bước từ tạo các kịch bản hành vi, sinh các test cases, sinh mã nguồn và sửa mã nguồn cho đến khi tất cả các test cases được thực hiện thành công. Kết quả của quá trình thử nghiệm được tóm tắt và đánh giá như sau:
- ChatGPT hỗ trợ nhà phát triển ngay từ bước cài đặt và thiết lập các tham số cần thiết cho môi trường chạy kiểm thử, giúp đơn giản hóa, tiết kiệm thời gian và công sức chuẩn bị môi trường.
- Việc thực hiện kiểm thử tự động ở những lần thử nghiệm đầu là không thành công do lỗi ở các chế tác mà chatGPT sinh ra như lỗi trong các tệp features, test cases, code. (Lưu ý: đây là bước thực thi kiểm thử không thành công do các kịch bản kiểm thử không khớp với các tệp features). Tuy nhiên, chúng tôi gửi các thông báo lỗi này cho chatGPT thì ChatGPT có thể phát hiện lỗi ở đâu và hướng dẫn cách sửa lỗi.
- ChatGPT có thể hỗ trợ các nhà phát triển sửa lỗi ở các chế tác liệt kê ở trên gồm features, test cases, code sao cho chúng khớp với nhau để có thể thực thi được các test cases. Chẳng hạn, trong quá trình làm thử nghiệm với hệ thống ATM đơn giản ở trên, ở một vài lần thực thi các test cases với Cucumber, chúng tôi đã nhận được một vài thông báo lỗi do ban đầu ChatGPT sử dụng cụm từ VND gắn với số tiền được mô tả trong features và mô tả trong các bước kiểm thử, dẫn đến Cucumber cho rằng thiếu một số bước kiểm thử do Cucumber không nhận diện được bước kiểm thử tương ứng. Cũng vậy, ban đầu mô tả features có chứa dấu phẩy trong số tiền, Cucumber không nhận diện được đó là số nguyên để khớp với đặc tả kiểu dữ liệu {int} trong mô tả bước kiểm thử. Chúng ta có thể nói cho ChatGPT về các lỗi mà Cucumber trả về này, ChatGPT sẽ giảng giải để chúng ta sửa đến khi chạy được test.
- Chúng tôi cũng đã cố tình đưa vào lỗi lập trình ở chương trình ATM.java, ví dụ thay vì trừ tiền khi user rút tiền thì chúng tôi sửa thành cộng thêm tiền trong tình huống đó. Khi Cucumber trả về thông báo test thất bại thì chúng ta có thể nói cho ChatGPT thông báo của Cucumber để ChatGPT giải thích nơi có lỗi trong chương trình và giúp chúng ta sửa lỗi. (Trong trường hợp này, bước thực thi kiểm thử đã chạy được thành công nhưng ca kiểm thử thất bại do chương trình không thỏa mãn ca kiểm thử).
- Có thể nói với quy trình BDD/TDD, ChatGPT như là một cộng sự, hỗ trợ chúng ta như một test designer để sinh các kịch bản hành vi và test cases cũng như test driver để có thể thực hiện test tự động với công cụ Cucumber. Ngoài ra, ChatGPT đóng vai trò như một cộng sự trong lập trình đôi (pair programming) sinh mã tự động dựa trên kịch bản hành vi và thỏa mãn các test cases đã định nghĩa trước.
Trong thử nghiệm này, chúng tôi sử dụng nhắm đến ứng dụng viết bằng ngôn ngữ Java và công cụ hỗ trợ kiểm thử tự động là Cucumber. Tuy nhiên, chúng ta có thể sử dụng ChatGPT để hỗ trợ các dự án viết bằng ngôn ngữ lập trình khác cũng như sử dụng công cụ kiểm thử khác.