- vừa được xem lúc

Học Ruby: Bài toán FizzBuzz và unit test

0 0 24

Người đăng: Hoàng Đức Quân

Theo Viblo Asia

Chào các bạn.

Sau bài khai bút đầu năm và làm 1 chút test ở LinkedIn về Ruby on Rails(đã passed), mình cảm thấy có lẽ nên quay về luyện tập với Ruby thuần lại 1 chút. Ngoài ra mình cũng mới thực sự để tâm tới chứng chỉ Ruby Silver và Ruby Gold(ở Nhật) nên mong là thời gian tới, mình sẽ cố gắng để học Ruby thuần không framework và có thể ghi lại những câu hỏi mà mình memo trong quá trình ôn luyện thành 1 bài viết để mọi người có thể đọc. Dự định bài viết mình định xây dựng sẽ không đơn thuần là kiểu học ôn rồi cho đáp án luôn hay tips, mà sẽ theo cách thử bằng code có test để nội dung đổi mới, đồng thời cũng để luyện tập luôn viết unit test. Rất mong mọi người đón đọc và góp ý nếu mình lỡ chệch đường viết kiểu: câu hỏi-đáp án-giải thích mà không có quá trình code.

Bài lần này mình sẽ tiếp cận lại bài toán FizzBuzz theo hướng của người đã có kinh nghiệm về Ruby.

image.png

Bài toán FizzBuzz

FizzBuzz là bài toán lập trình về câu lệnh điều kiện mình nghĩ ai học code cũng phải từng trải qua. Nhập các số nguyên vào làm input. Nếu là số chia hết cho 3, chúng ta sẽ có Fizz; chia hết cho 5 là Buzz và chia hết cho cả 3 lẫn 5 là FizzBuzz. Các trường hợp còn lại sẽ trả lại đúng giá trị input.

Xử lý bài toán

Nếu như ở sách thì chắc chắn chúng ta sẽ được hướng dẫn viết chương trình luôn, sau đó quay ngược trở lại viết unit test.

Nhưng ở đây là người có kinh nghiệm về Ruby rồi, nên tự bản thân mình có bảo:

Thế nên các bước mình sẽ làm ngắn gọn như sau:

Viết test case

Trước tiên, mình sẽ làm thư mục có cấu trúc như sau:

|-lib/
|--fizz_buzz.rb
|-test/
|--fizz_buzz_test.rb

Và test case viết ra mình sẽ cho vào thư mục test. Còn chương trình sẽ để vào thư mục lib/.

Ở đây thì mình sẽ dùng gem 'minitest' mặc định thôi nên viết ở fizz_buzz_test.rb sẵn như sau:

require 'minitest/autorun'
require './lib/fizz_buzz' class FizzBuzzTest<Minitest::Test def test_fizz_buzz # test cases here end
end

Tiếp đây chúng ta sẽ phân tích: yêu cầu là có 4 trường hợp: chia hết cho 3, chia hết cho 5, chia hết cho 15 và có dư. Vậy nên ít nhất chúng ta phải có các case là 1, 3, 5, 15.

Để kiểm tra được tốt hơn thì mình sẽ lấy thêm 1 case 6 ở Fizz, case 10 ở Buzz. Case FizzBuzz mình sẽ lấy thêm 30.

Và với case trả nguyên số thì mình sẽ lấy 2,4. Nếu để gọn thì chỉ cần lấy thêm 1. Nhưng mình nghĩ ở đây liền thứ tự sẽ đẹp bài hơn

Và cứ theo yêu cầu ta có:

require 'minitest/autorun'
require './lib/fizz_buzz' class FizzBuzzTest<Minitest::Test def test_fizz_buzz assert_equal '1', fizz_buzz(1) assert_equal '2', fizz_buzz(2) assert_equal 'Fizz', fizz_buzz(3) assert_equal '4', fizz_buzz(4) assert_equal 'Buzz', fizz_buzz(5) assert_equal 'Fizz', fizz_buzz(6) assert_equal 'Buzz', fizz_buzz(10) assert_equal 'Fizz Buzz', fizz_buzz(15) assert_equal 'Fizz Buzz', fizz_buzz(30) end
end

Viết xong rồi thì bước tiếp theo là chạy thử bằng ruby test/fizz_buzz_test.rb . Đừng mong đợi lần này chạy success, vì chúng ta đã viết code chính quái đâu.

Viết code chính

Giờ chúng ta quay qua code chính ở fizz_buzz.rb

def fizz_buzz(n) if n % 15 == 0 'Fizz Buzz' elsif n % 3 == 0 'Fizz' elsif n % 5 == 0 'Buzz' else n.to_s end
end

Bài cũng khá đơn giản và nhanh. Lúc này thì chạy test kia chắc chắn là pass rồi. Và chạy thử chương trình chắc chắn cũng ổn.

Vậy bày đặt viết test case làm gì?

Yêu cầu bổ sung: không dùng if else

Mình nghĩ cái này mọi người gặp nhiều rồi. Phổ biến nhất là coding convention ở trong Ruby. Có các tình huống khác là nâng cấp version Rails/Ruby lên. Khi đó test case đóng vai trò quan trọng trong việc xác nhận hệ thống hoặc code viết ra có cho ra output mong muốn hay là không. Nếu không có test case trong trường hợp này thì công sức bạn bỏ ra để chạy thử toàn hệ thống thao cách thủ công sẽ rất lớn(Mình không đảm bảo test case chạy đúng thì hệ thống sẽ hoạt động đúng mà chỉ là phần lớn thôi. Nhưng thế cũng là 1 độ yên tâm cao để những phần test không cover được ta sẽ test bằng tay).

Ở đây thì yêu cầu sau khi đem code fizz_buzz.rb kia submit lên hệ thống, bạn bị review code lại với comment ở Github: KHÔNG DÙNG IF ELSE Ở ĐÂY!

Lúc này đơn giản là thay đổi code lại dùng case ... when. Và để kiểm tra hệ thống chạy đúng như kq cũ ko chúng ta sẽ chạy lại chương trình bằng tay mất khoảng gần 1 phút với việc gõ từng case... hoặc là chạy test viết ở trên chưa đến 10s.

Chương trình sẽ được viết lại như sau:

def fizz_buzz(n) case when n % 15 == 0 'Fizz Buzz' when n % 3 == 0 'Fizz' when n % 5 == 0 'Buzz' else n.to_s end
end

Đó. Bây giờ chạy lại kiểu gì thì cũng ổn rồi!

Kết luận

Như vậy là mình đã áp dụng practice viết test trước, viết code sau với 1 bài toán FizzBuzz đơn giản. Hẹn gặp lại các bạn ở bài viết tiếp theo

Bình luận

Bài viết tương tự

- vừa được xem lúc

Bài toán tìm đường đi ngắn nhất với giải thuật Dijkstra

Với các bạn sinh viên chuyên ngành công nghệ thông tin, chắc không lạ gì với bài toán tìm đường đi ngắn nhất (Shortest Path Problems) trong đồ thị trọng số nữa. Ở bài viết lần này, mình sẽ làm 3 việc:.

0 0 122

- vừa được xem lúc

Tôi cá là bạn không biết những điều này - Ruby on rails ( Phần 2)

Các bạn có thể theo dõi phần 1 ở đây :. https://viblo.asia/p/toi-ca-la-ban-khong-biet-nhung-dieu-nay-ruby-on-rails-phan-1-WAyK8DDeKxX. 5.

0 0 211

- vừa được xem lúc

Những thay đổi trong ruby 3.0

. 2020 là một năm lớn đối với cộng đồng Ruby. Những người sáng lập Ruby có một món quà thực sự tuyệt vời cho chúng ta vào giáng sinh với việc phát hành Ruby 3.

0 0 31

- vừa được xem lúc

Có gì đặc biệt trong phiên bản Ruby 3x3 ?

Hello guys, chắc hẳn thời gian vừa rồi chúng ta cũng đã nghe qua thông tin Ruby sắp cho ra mắt Ruby version 3, hay còn được gọi là ruby 3x3, vậy liệu Ruby version 3 này có gì mới, và có những update nào đáng phải kể đến, và tại sao mọi người lại gọi nó là ruby version 3x3, thì trong bài ngày hôm nay

0 0 30

- vừa được xem lúc

Cách sử dụng class Time & Date trong Ruby (Phần 1)

Time là một class trong Ruby, nó sẽ giúp chỉnh sửa format, trích xuất thông tin một cách hiệu quả theo ý của bạn. . Topic hôm nay chúng ta có gì nào. .

0 0 83

- vừa được xem lúc

Ruby 3.0 có gì mới

Ruby 3.0.0 đã được ra mới được ra mắt vào tháng 12/2020, mục tiêu của bản 3.0.

0 0 26