Sự khác nhau giữa TDD và BDD trong kiểm thử phần mềm

Là một Tester trong công ty USA đang áp dụng mô hình TDD và BDD nên mình muốn chia sẻ hiểu biết của mình về Test-Driven Development (TDD) và Behavior-Driven Development (BDD) – mô hình phát triển phần mềm hướng kiểm thử (test oriented) theo tinh thần Agile đang được áp dụng rộng rãi.

1. TDD là gì?

Chính xác với nghĩa đen của nó: “Test-Driven Development” có thể được tạm hiểu là mô hình phát triển với trọng tâm hướng về việc kiểm thử. TDD được xây dựng theo hai tiêu chí: Test-First (Kiểm thử trước) và Refactoring (Điều chỉnh mã nguồn). Trong đó, khi một yêu cầu phần mềm (requirement) được đặt ra:

  • Người developer soạn thảo kịch bản kiểm thử (test case) cho yêu cầu đó trước tiên và chạy thử kịch bản đó lần đầu tiên. Hiển nhiên, việc chạy thử sẽ đưa ra 1 kết quả thất bại vì hiện tại chức năng đó chưa được xây dựng (và thông qua kết quả đó, ta cũng kiểm tra được là kịch bản kiểm thử đó được viết đúng).
  • Theo đó, dựa vào mong muốn (expectation) của kịch bản kia, người developer sẽ xây dựng một lượng mã nguồn (source code) vừa đủ để lần chạy thứ 2 của kịch bản đó thành công.
  • Nếu trong lần chạy thứ 2 vẫn đưa ra 1 kết quả thất bại, điều đó có nghĩa là thiết kế chưa ổn và người developer lại chỉnh sửa mã nguồn và chạy lại kịch bản đến khi thành công.
  • Khi kịch bản kiểm thử được chạy thành công, người developer tiến hành chuẩn hóa đoạn mã nguồn (base-line code) và tiếp tục hồi quy với kịch bản kiểm thử tiếp theo. Việc chuẩn hóa bao gồm thêm các comment, loại bỏ các dư thừa, tối ưu các biến…

Sự khác nhau giữa TDD và BDD trong kiểm thử phần mềm | Anh Tester

Quy trình phát triển TDD vẽ bởi Colin Kloes, đề cập vấn đề khó khăn trong việc hiểu rõ yêu cầu chức năng trước khi viết kịch bản kiểm thử.

Phương châm của TDD: "Red - Green - Refactor"

  • "Red": tạo ra unit test và chạy nó để xem nó fail như thế nào
  • "Green": Thực thi logic code để hoàn thành test
  • "Refactor": cải thiện code, tránh dupplicate (trùng lặp), cải thiện kiến trúc test để kết quả test là thành công

Test được viết trước khi logic code thực tế được thực thi, TDD đảm bảo chất lượng cao cho sản phẩm và giúp đội phát triển tập trung vào việc viết code đơn giản và dễ hiểu. Unit test tập trung vào các khái niệm bên trong code của ứng dụng, vì vậy những nhà phát triển bên ngoài sẽ khó hiểu chúng. Hơn nữa, việc đánh giá các khái niệm, độ bao phủ code cũng như chất lượng của unit test trước khi thực hiện kiểm thử tích hợp cũng gặp nhiều khó khăn. Đó là lý do tại sao toàn bộ trách nhiệm cho unit test không chỉ thuộc về QA, mà còn của Developer, unit test xử lý low-level code blocks và yêu cầu kiến thức về kiến trúc ứng dụng phần mềm.

Nhược điểm:

  • Một số developers vẫn còn tư duy Testing là một sự lãng phí thời gian
  • Việc tạo thêm Test code làm tăng thời gian phát triển sản phẩm
  • Việc thực thi test có thể dễ dàng thực hiện sai cách, chỉ test các methods, class cụ thể riêng biệt, nhưng chưa test hệ thống nói chung

Ưu điểm:

  • Hiểu rõ về logic hoạt động của code
  • Tăng chất lượng code, do developer có thể cấu trúc lại code bất kỳ lúc nào và kiểm tra tính chính xác của code
  • Giảm thiểu các tickets do QA trả về cho dev
  • Giảm sự xuất hiện của các lỗi tương tự


2. Điểm khác biệt của TDD với một mô hình truyền thống Waterfall là gì?

Thông qua quy trình TDD trình bày ở trên, ta có thể dễ dàng nhận ra là thứ tự các bước xây dựng 1 tính năng phần mềm gần như đã được đảo ngược so với 1 quy trình truyền thống. Vậy điều này giúp ích gì và có gì hay hơn?

Trước hết, hãy nhìn lại 1 mô hình thác đổ (Waterfall Model) thông thường: việc phân tích các yêu cầu (requirements) thường được tiến hành bởi Business Analyst (BA) 1 cách chuyên hóa và khi đến giai đoạn xây dựng (implementing phase) thì đa phần các developer tiếp xúc với các yêu cầu phần mềm dưới dạng các bản thiết kế. Họ chỉ quan tâm đến đầu vào, đầu ra (Input, Output) của tính năng mình xây dựng mà thiếu đi cái nhìn thực tiễn từ góc nhìn người dùng (end-users). Một hệ quả tất yếu là lỗi phần mềm đến từ việc sản phẩm ko tiện dụng với người dùng.

Cùng với Agile, việc ứng dụng TDD góp phần làm gần khoảng cách giữa đội ngũ thiết kế phần mềm và sản phẩm thực tiễn, tối ưu quy trình. Cụ thể như sau:

  • Thông qua kịch bản kiểm thử, developer có cái nhìn trực quan về sản phẩm ngay trước khi xây dựng mã nguồn. Sản phẩm họ tạo ra chính xác và gần gũi người dùng hơn.
  • Phần mã nguồn được thêm vào chỉ vừa đủ để chạy thành công kịch bản kiểm thử, hạn chế dư thừa và qua đó hạn chế khả năng xảy ra lỗi trên những phần dư thừa.
  • Bảo đảm mã nguồn luôn phản ánh đúng và vừa đủ yêu cầu phầm mềm, hạn chế được công sức tối ưu mã nguồn về sau.


3. TDD và Agile

Trong quá trình hình thành, TDD có liên quan mật thiết đến khái niệm “Test-First Programming” trong mô hình eXtreme Programming “XP” thuần túy Agile – thịnh hành từ năm 1999. Tuy nhiên, bằng việc ứng dụng đa dạng và linh hoạt, TDD cũng có những đặc điểm và tùy biến của riêng nó (mình sẽ trình bày rõ hơn bên dưới).

Sự khác nhau giữa TDD và BDD trong kiểm thử phần mềm | Anh Tester(TDD trong Agile framework phác họa bởi Mohammad Sami)

TDD đáp ứng “Tuyên ngôn về Agile” khi bản thân quy trình TDD thúc đẩy tính thực tiễn của sản phẩm, tương tác với người dùng. Để phát huy tối đa những lợi ích mà TDD mang lại, độ lớn của 1 đơn vị tính năng phần mềm (unit of function) cần đủ nhỏ để kịch bản kiểm thử dễ dàng được xây dựng và đọc hiểu, công sức debug kịch bản kiểm thử khi chạy thất bại cũng giảm thiểu hơn.

Thực tế cho thấy một số sự kết hợp giữa TDD và mô hình Agile khác như Scrum có thể hỗ trợ và tối ưu lợi ích của nhau. Ví dụ, việc chia nhỏ Backlog thành các User Story của Scrum khiến việc xây dựng kịch bản kiểm thử hướng TDD trở nên dễ dàng và thuận tiện. Thêm vào đó, cả Scrum và TDD tương đồng trong việc loại bỏ sự chuyên hóa về vai trò của bộ đôi Developer – Tester. Vì lý do đó, đôi lúc có thể bạn sẽ thấy vừa TDD vừa Scrum được áp dụng trong cùng 1 dự án.


4. Behavior-Driven Development – BDD

Như vậy, trong mô hình TDD nhiệm vụ kiểm thử do developer đảm nhiệm và vai trò chuyên hóa của người tester gần như không còn nữa. Chắc hẳn các bạn sẽ tự hỏi: “Vậy một Acceptance Tester như chúng ta có vai trò gì trong mô hình?”, “Tại sao tôi phải hiểu về TDD khi người ta ko cần tôi trong quy trình đó?”

Quả thực, trong mô hình TDD người Acceptance Tester thực sự đã chết. Tuy nhiên, việc cộng gộp vai trò phát sinh vấn đề quá tải cho người developer. Để làm tốt công việc, xuyên suốt chu trình người developer phải chú ý thêm những vấn đề thuần túy của kiểm thử (test) như: “Cái gì cần test và cái gì không?” “Viết bao nhiêu kịch bản là đủ?” “Làm sao để hiểu là test đó thất bại?” “Bắt đầu test từ đâu?” …

Để giải quyết vần đề phát sinh mà vẫn tận dụng triệt để lợi ích mà TDD mang lại, Dan North phát triển một mô hình mới với tên gọi: Behavior-Driven Development – BDD (hoặc ta có thể hiểu là Acceptance Test-Driven Development – ATDD). Trong đó, một vai trò mới trong việc thiết kế kiểm thử (Test Design) được đặt ra:

  • Thay vì chờ đợi sản phẩm hoàn thành và kiểm thử, người Tester/Analyst tham gia vào quá trình xây dựng mã nguồn với vai trò phân tích và xây dựng hệ thống kịch bản kiểm thử dưới góc độ ngôn ngữ tự nhiên dễ hiểu từ các yêu cầu (requirement).
  • Đồng thời, họ giúp đỡ developer trong việc giải thích và đưa ra các phương án xây dựng mã nguồn mang tính thực tiễn với người dùng ngay trước khi bắt tay xây dựng.
  • Người developer liên hệ mật thiết với người tester và xây dựng mã nguồn với những phương án mà tester cung cấp theo mô hình TDD.
  • Kịch bản kiểm thử được phân chia làm 2 lớp: Lớp chấp nhận (feature/acceptance test) và Lớp đơn vị (unit test).
  • Theo đó, kịch bản kiểm thử lớp đơn vị mang thuần tính thiết kế và phục vụ cho việc kiểm thử lớp đơn vị (Unit test) còn kịch bản kiểm thử lớp chấp nhận có thể được tái sử dụng cho quá trình kiểm thử hồi quy về sau (Regression Test)

Sự khác nhau giữa TDD và BDD trong kiểm thử phần mềm | Anh Tester

(Mô hình BDD – TDD trong Agile mô phỏng bởi Paul Littlebury)


Các bước thực hiện:

  • Viết kịch bản test
  • Chạy kịch bản test và kiểm tra cách hoạt động của hệ thống
  • Xác định các tình huống khi thực hiện kịch bản
  • Kiểm tra các tình huống này, nhận biết những gì hoạt động không đúng
  • Xác định và thực hiện các chức năng tối thiểu cần thiết cho tất cả các ví dụ để test
  • Thực hiện test nhiều lần, nếu có lỗi lặp lại bước trên
  • Kịch bản hoạt động, thực hiện tạo lịch bản mới để coverage những yêu cầu chính

Nhược điểm:

  • Yêu cầu hiểu sâu về số lượng lớn các khái niệm, vì vậy muốn tiếp cận với BDD thì yêu cầu developers cần hoàn toàn hiểu rõ về TDD
  • Vì nó là một khái niệm, biến nó thành một kỹ thuật thực hành hoặc kết nối nó với một bộ công cụ có nghĩa là hủy hoại nó

Ưu điểm:

  • Nhờ có sự hiểu biết và cách nhìn tổng quan mà đội phát triển tập trung vào các tính năng ưu tiên từ khách hàng
  • Giúp developers tập trung vào nhu cầu của người dùng và hành vi mong đợi thay vì đi vào sâu tất cả các chi tiết không cần thiết của sản phẩm
  • Đội phát triển tập trung cụ thể vào chi tiết các chức năng và kiển tra những thứ quan trọng thay vì viết test cho toàn bộ code
  • Đòi hỏi sự tăng trưởng liên tục trong sự hiểu biết về các yêu cầu sản phẩm, làm cho sự phát triển của các ứng dụng thay đổi dễ dàng hơn


Từ mô hình trên ta dễ dàng nhìn nhận được sự ưu việt BDD mang lại đặc biệt là trong các dự án phần mềm lớn và phức tạp, khi cả hai khía cạnh phân hóa vai trò và chất lượng phải đi đôi. Ngoài ra, việc chạy kịch bản kiểm thử và xử lý sớm các vấn đề thiết kế ngay trong khâu xây dựng giúp giảm thiểu tối đa chi phí và công sức sữa chữa lỗi.

Trong khi khái niệm BDD mang tính lý thuyết, việc ứng dụng của nó lại đặt nặng sự thực nghiệm. Để phát huy lợi ích về thời gian trong việc xây dựng kịch bản kiểm thử, ngôn ngữ và cách truyền tải là 1 thử thách khi phải đáp ứng khả năng đọc hiểu từ cả 2 khía cạnh: tự nhiên và thiết kế. Bằng sự vay mượn từ ngôn ngữ viết User Story, ngôn ngữ Gherkin được phát triển để phục vụ nhu cầu đó với cấu trúc đơn giản, hướng đối tượng và tương đồng cho mọi kịch bản: Given – When – Then (mình sẽ trình bày rõ hơn về ngôn ngữ này ở các loạt bài khác)

Sự khác nhau giữa TDD và BDD trong kiểm thử phần mềm | Anh Tester

 

Nên sử dụng TDD hay BDD?

Bây giờ sự khác biệt đã được giải quyết giữa các cách tiếp cận này, vậy bạn nên sử dụng cách nào? Bạn có thể sử dụng thử nghiệm riêng từng phương pháp, và sự lựa chọn giữa chúng sẽ phụ thuộc vào cái mà team muốn hướng tới nhiều hơn và trải nghiệm nó với kiểm thử đơn vị. Điều được nhắc đến ở đây đó là nhiều kỹ thuật trong TDD sẽ được sử dụng trong BDD, vì vậy lời khuyên dành cho các bạn đó là nên thử nghiệm với TDD trước. Nếu bạn trải nghiệm với TDD nhưng chưa đạt được kết quả như mong đợi thì hãy thử với BDD. Hoặc kết hợp sử dụng chúng để bổ sung cho nhau cũng là cách rất độc đáo và hiệu quả.

Việc sử dụng TDD và BDD mang lại cho đội phát triển một lợi thế đáng kể trong việc tạo ra ứng dụng. Vì vậy hãy vận dụng và kết hợp chúng một cách có hiệu quả để tạo ra những sản phẩm mang lại nhiều giá trị cho người dùng.


Nguồn tham khảo:

  • Anh Tester

    Đường dẫu khó chân vẫn cần bước đi
    Đời dẫu khổ tâm vẫn cần nghĩ thấu