Test Driven Development

Posted in General on December 03, 2015 by manhhomienbienthuy Comments
Test Driven Development

Test-driven development (TDD) là một kỹ thuật tiên tiến sử dụng các unit test tự động để dẫn dắt quá trình design và phát triển phần mềm và tách biệt các phụ thuộc. Kết quản của việc sử dụng kỹ thuật này là một bộ đầy đủ các test có thể chạy bất cứ lúc nào để đảm bảo rằng phần mềm vẫn hoạt động chính xác. Kỹ thuật này được nhấn mạnh bởi những người sử dụng phương pháp phát triển Agile.

Giới thiệu test tự động

Thế nào là test tự động?

Test là một công việc chúng ta thường xuyên làm, để kiểm tra hoạt động của những dòng code chúng ta viết ra.

Test có thể được thực hiện ở nhiều mức độ. Một số test chỉ tập trung vào phần chi tiết rất nhỏ của code (method này có trả về kết quả như dự kiến hay không?), trong khi có những test kiểm tra hoạt động tổng thể của toàn dự án (những input như thế này từ người dùng có cho ra kết quả đúng như mong đợi hay không?). Không có sự phân biệt cách bạn test bằng cách chạy console để kiểm tra các hàm viết ra, hay bạn chạy cả chương trình và điền dữ liệu chạy thử để xem kết quả. Chúng đều là test.

Thứ làm cho test tự động khác biệt đó là việc test được thực hiện hoàn toàn bằng máy tính. Bạn tạo ra một tập các test cần thiết, và sau đó, bạn thay đổi ứng dụng, bạn có thể kiểm tra code của bạn vẫn hoạt động đúng như ban đầu, hoàn toàn bằng máy tính chứ không cần thực hiện bằng tay.

Tại sao lại phải viết test?

Một câu hỏi đặt ra là tại sao lại phải viết test? Có thể bạn cảm thấy rằng, bạn chỉ cần học lập trình các app bằng framework như Rails, Django, Laravel là đủ và việc học thêm các thứ linh tinh khác là quá tải và không cần thiết. Và chỉ cần học lập trình ra các app là đủ, nó chạy rất tốt. Tốn thời gian cho việc học và viết test có làm nó chạy tốt hơn không? Nhưng hãy xem qua những lý do dưới đây, bạn sẽ suy nghĩ lại.

Test tiết kiệm thời gian cho bạn

Vào một thời điểm bất kỳ nào đó, bạn sẽ cần test rằng mọi thứ đang hoạt động bình thường. Trong những ứng dụng phức tạp, có thể sẽ có hàng trăm tương tác lẫn nhau giữa các thành phần trong ứng dụng đó.

Một thay đổi rất nhỏ trong 1 trong các thành phần đó có thể dẫn đến những hoạt động bất thường của cả ứng dụng. Kiểm tra nó "vẫn hoạt động tốt" có nghĩa các chức năng của code vẫn hoạt động với hàng chục biến thể khác nhau của dữ liệu đầu vào để đảm bảo rằng, bạn chưa phá hỏng thứ gì đó và hệ thống hoạt động bình thường. Đó không phải là cách làm thông minh cho lắm.

Trường hợp này, việc test tự động có thể giúp bạn làm những việc đó chỉ trong vài giây. Nếu có thứ gì đó bị phá hỏng, test cũng sẽ giúp bạn tìm ra code gây ra những hoạt động bất thường.

Đôi khi nó giống như một việc vặt vãnh khiến bạn tách khỏi công việc lập trình đầy sáng tạo để đối mặt với công việc viết test tẻ nhạt và nhàm chán, đặc biệt khi bạn đã hiểu rất rõ code của mình hoạt động hoàn toàn bình thường.

Tuy nhiên, việc viết test có ý nghĩa hơn rất nhiều việc bạn bỏ ra hàng giờ đồng hồ để test hệ thống bằng tay và cố gắng tìm ra nguyên nhân của vấn đề.

Test không chỉ tìm ra vấn đề, nó còn phòng tránh chúng

Thật là một sai lầm nếu có những suy nghĩ tiêu cực về test, rằng nó là một khía cạnh tiêu cực của quá trình phát triển ứng dụng.

Không có test, mục đích hoặc hành vi của ứng dụng có thể rất mơ hồ. Kể cả đó là code của bạn, có những lúc chính bạn cũng không hiểu được chính xác nó đang làm những gì.

Test có thể thay đổi điều đó. Nó làm rõ ràng code của bạn từ bên trong, và khi có bất thường xảy ra, nó chỉ tập trung vào phần đã gây ra lỗi, cho dù bạn có nhận ra rằng nó đã hoạt động không còn đúng nữa hay không.

Test làm code của bạn hấp dẫn hơn

Bạn có thể tạo ra những ứng dụng rất khủng, với những công nghệ tiên tiến nhất. Nhưng các developer khác không thèm để ý đến chúng chỉ vì chúng thiếu test. Không có test, không có gì để họ tin tưởng vào ứng dụng của bạn, không có gì để đảm bảo ứng dụng của bạn hoạt động đúng với những tính năng khủng mà bạn nói. Có thể nói rằng, khi bạn code mà không viết test, thì ứng dụng của bạn đã chết từ khi chưa bắt đầu.

Khiến những người khác để ý đến ứng dụng của bạn cũng là một lý do cho bạn thấy rằng viết test là một việc rất quan trọng.

Test giúp team làm việc cùng nhau

Những điểm ở trên được viết dưới góc nhìn của một developer phát triển ứng dụng một mình. Những ứng dụng phức tạp thì một người không thể làm hết được, nó sẽ được phát triển bởi một team. Và test sẽ giúp đảm bảo rằng những người chung team với bạn trong quá trình làm việc của họ không phá hỏng thứ gì đó bạn vừa làm được (và bạn cũng không phá hoại những gì họ làm). Nếu bạn muốn trở thành developer giỏi, bạn cần phải viết test giỏi.

Chiến thuật test cơ bản

Có nhiều cách tiếp cận khác nhau cho việc viết test.

Nhiều người lập trình theo một mô hình gọi là "test-driven development". Họ viết test của họ trước sau đó sẽ viết code. Việc này nghe có vẻ rất ngược đời nhưng thực ra nó đúng là những gì chúng ta thường làm. Chúng ta khi làm việc gì đó, chúng ta phải xác định vấn đề cần giải quyết, sau đó chúng ta viết code để giải quyết vấn đề đó. Có thể nói rằng đây là quá trình rất tự nhiên, và test-driven development chỉ đơn giản là tiêu chuẩn hóa quá trình đó thông quá các test case được viết ra.

Một trường hợp dễ gặp hơn với những người mới lập trình, đó là họ thường viết code trước, sau đó mới viết test. Đương nhiên việc viết test trước vẫn tốt hơn, nhưng không bao giờ là quá muộn để làm việc đó.

Đôi khi bạn cảm thấy khó khăn khi không biết phải bắt đầu viết test từ đâu. Nếu bạn đã viết ra hàng nghìn dòng code, việc chọn test cho chỗ nào đúng là không dễ dàng gì. Trong những trường hợp như vậy, tôi nghĩ bạn nên viết test vào lần tới khi bạn thay đổi code, có thể là bạn thêm tính năng hay fix một bug nào đó.

Test-driven development

Test-driven development is a programming technique that requires you to write actual code and automated test code simultaneously. This ensures that you test your code — and enables you to retest your code quickly and easily, since it's automated.

Cách thực hiện

Test-driven development (gọi tắt là TDD) là một chu trình phát triển phần mềm, trong chu trình đó, chúng ta sẽ làm những việc như dưới đây.

  1. Trước khi thực sự bắt tay vào viết code, trước tiên, bạn phải viết các test cho code của bạn. Bạn phải viết các test bao phủ tất cả các trường hợp khác nhau của dữ liệu đầu vào, dữ liệu ra và các lỗi có thể xảy ra trong quá trình xử lý. Đây là thời điểm thích hợp để viết test, vì khi đó, bạn chưa bị ảnh hưởng bởi những dòng code mình viết ra.
  2. Lần đầu tiên chạy test, nó sẽ fail. Nó cần phải fail bởi lúc này bạn chưa code gì cả. Nếu nó không fail có nghĩa là vấn đề đã được giải quyết và bạn không cần làm gì nữa.
  3. Bây giờ, bạn có thể bắt tay vào lập trình. Bởi vì bạn đã có test ở trên, bạn sẽ code đến khi nào tất cả các test đều pass hết. Nếu vẫn còn test fail có nghĩa là code của bạn vẫn chưa hoàn thiện và nó vẫn cần được code tiếp.
  4. Khi code của bạn đã pass hết các test, bạn có thể refactor chúng cho đẹp hơn. Bạn không cần phải lo lắng quá nhiều rằng có thể nó sẽ tạo ra bug. Bởi vì đã có test ở trên, chừng nào code của bạn còn pass hết các test nghĩa là nó vấn hoạt động tốt.
  5. Lặp lại quy trình trên với thành phần tiếp theo của chương trình.

tdd

Best practices

Được thiết kế như là một nhánh của lập trình cực độ (XP), TDD đi theo phương pháp linh hoạt trong việc phát triển phần mềm trong các tương tác và liên quan đến design và code đơn giản, sạch đẹp.

Dưới đây tôi đề xuất một số best practices cần được tuân theo trong project.

Tránh sự phức tạp trong tính năng

Hãy giữ những tính năng đơn giản nhất có thể. Hãy suy xét cẩn thận cùng với cả team để đảm bảo rằng các test case bao phủ được toàn bộ tính năng với tất cả những trường hợp khác nhau của đầu vào và đầu ra. Bởi vì chúng ta đang phát triển phần mềm dựa vào test, nên chúng cần được review cẩn thận.

Tập trung vào mục tiêu bạn cần đạt được

Hãy chắc chắn rằng bạn hiểu code của bạn giải quyết vấn đề gì và nó được gọi khi nào để tạo các test case phù hợp. Hãy đảm bảo các test case tuân thủ các quy tắc đặt tên hàm, biến và chúng miêu tả một cách chính xác và rõ ràng những gì bạn cần thực hiện, mục tiêu bạn cần đạt được. Điều này rất quan trọng bởi các tính năng sẽ được thêm vào liên tục cùng với các tương tác khác nhau với người dùng. Sau này, những developer có thể nhìn vào test case và dễ dàng hiểu được tính năng này làm gì.

Duy trì code đơn giản

Hãy đảm bảo rằng code của bạn vừa đủ để thỏa mãn các test case, không thiếu không thừa. Đây là một nguyên lý rất cơ bản của TDD. Điều này sẽ giúp giảm thiểu các khiếm khuyết tiềm ẩn và cũng đơn giản hóa quá trình review và test. Tuy nhiên phải đảm bảo code dễ đọc, dễ hiểu và có thể cải tiến trong tương lai.

Test đi test lại

Test trước vào sau khi code, test một lần nữa sau khi refactor. Điều này để đảm bảo rằng code không bị phá hỏng trong bất cứ một bước nào. Trong khi refactor, hãy đảm bảo code mới có thể bảo trì và tuân thủ các quy tắc coding convention. Quy tắc ở đây chính là test đi test lại test bất cứ khi nào code thay đổi hoặc code được merge.

Duy trì code bất khả xâm phạm

Hãy sử dụng các công cụ quản lý version (git, svn, ...) đề check out và check in code. Điều này rất quan trọng, nhất là khi có nhiều developer cùng làm việc với code. Hãy sử dụng một số công cụ tích hợp như Jenkins đề tránh các vấn đề khi merge code.

Có hiểu biết về ứng dụng

Trong TDD, code cần được giữ đơn giản nhất nhưng đủ hiệu quả đề đạt được mục đích của chúng mà không làm hỏng thứ gì khác. Hơn nữa, code mới nên pass các test từ càng sớm càng tốt. Hãy duy trì các tài liệu về hệ thống, bao gồm cả việc lưu trữ các test case. Và với các thành viên trong team đều có kiến thức tốt về ứng dụng sẽ đảm bảo project hoạt động trơn tru và thành công.

Biết khi nào thì dùng TDD

Đây là điều cuối cùng tôi muốn nói. TDD cũng giống như các chu trình phát triển phần mềm khác, sẽ phát huy tác dụng tốt nhất trong một số hoàn cảnh nhất định. Sử dụng TDD trong quá trình phát triển sẽ giúp test nhanh. Bất cứ test nào phức tạp và cần nhiều thời gian sẽ là ngược lại với mục đích của TDD.

Với TDD, quá trình phát triển được kiểm soát chặt chẽ và kết quả là, các khiếm khuyết được giảm thiểu. Test đi test lại để đảm bảo rằng các thành phần trong hệ thống hoạt động chính xác.

I apologise for any typos. If you notice a problem, please let me know.

Thank you all for your attention.