Autotest GUI với Scala

Scala không phải là một ngôn ngữ mới nhưng vẫn còn khá lạ lẫm với các developer , đặc biệt là việc áp dụng Scala trong viết test. Ngày càng có nhiều dự án sử dụng Scala cho mục đích test GUI, vì vậy bài viết sẽ giới thiệu một sự kết hợp hoàn hảo giữa Scala, Junit, Specs2 và Selenium để đạt được điều đó.

Trong quá trình tham gia project tôi luôn tự hỏi vì sao họ lại kết hợp những thứ này với nhau. Với Junit và Selenium thì câu trả lời là tương đối dễ dàng bởi:

Junit: là một framework unit test cho Java, hỗ trợ cấu hình và chạy các unit test, nó phổ biến đến nỗi khi nhắc đến viết unit test cho Java thì người ta sẽ nhắc ngay đến nó. Scala lại là ngôn ngữ được biên dịch qua mã Java byte code rồi chạy trên JVM (Java virtual machine) nên 2 ngôn ngữ này có thể kết hợp với nhau hoặc có thể sử dụng các framework, thư viện của nhau. Do vậy việc tận dụng một framework phổ biến, đã được cộng đồng kiếm chứng làm giảm chi phí phát triển dự án

Selenium: để có thể thực hiện autotest GUI thì cần phải có một tool cho phép giả lập các thao tác của người dùng với browser như click chuột, nhập text, gõ các phím ... Selenium chính là một tool như vậy, bạn có thể làm những điều này dễ dàng với Selenium trên các trình duyệt khác nhau như firefox, chrome, ie... Cũng giống như Junit nó là một tool phổ biến và hỗ trợ đầy đủ nhất cho mục đích này.

Vậy tại sao lại sử dụng Scala mà không phải là Java? Khi viết test GUI ngoài việc đảm bảo viết và chạy các test đúng thì điều quan trọng nhất là các test case phải ngắn gọn dễ đọc, dễ bảo trì. Điều này thì Scala hơn hẳn Java, Scala cung cấp các built-in method, sử dụng closure và lamda giống như trong Ruby hay Python, làm cho code viết bằng Scala ngắn gọn, xúc tích và dễ đọc ngay cả với những tester ít có kinh nghiệm lập trình, do nó gần với ngôn ngữ tự nhiên hơn so với Java. Dưới đây là một số ví dụ:

Nếu muốn khai báo một list các số nguyên, sau đó lọc những phần tử chẵn rồi sắp xếp:

val nums = List(5, 1, 4, 3, 2)
nums.filter(_ % 2 == 0).sort(_ < _)

Hoặc một thao tác hay gặp khi viết các test là kiểm tra xem liệu một list có được sắp xếp theo chiều giảm dần hay không?

return list.view.zip(list.tail).forall(x => x._1 <= x._2)

Hay muốn convert một list các String sang list các số Double:

def convertStringListToDoubleList(list: Seq[String]) = {
    list.map({e => e.toDouble})
}

Như vậy chỉ cần sử dụng Junit, Selenium và Scala là đã đủ đồ nghề cho chúng ta viết test. Tuy nhiên nếu chỉ có vậy thì các test case viết sẽ chỉ có code scala, nó có thể ngắn gọn và dễ đọc hơn với những người ít nhiều có kinh nghiệm với lập trình, tuy nhiên vấn đề đặt ra bây giờ là làm thế nào để test có thể dễ đọc, dễ hiểu với ngay cả những người không biết code. Tức là các test khi code xong phải gần giống như các test khi được đặc tả, nó phải gần giống như một file text. Specs2 là một thư viện cho phép đặc tả các unit test và acceptance test. Nó cũng cung cấp các matcher giúp việc assert các kết quả mong đợi và kết quả thực tế khi chạy thuận tiện và dễ đọc hơn. Hãy xem xét một test case được viết bằng Specs2 dưới đây:

class HelloWorldSpec extends Specification { def is = s2"""

  This is a specification for the 'Hello world' string

  The 'Hello world' string should
    contain 11 characters                             $e1
    start with 'Hello'                                $e2
    end with 'world'                                  $e3
                                                      """
  def e1 = "Hello world" must haveSize(11)
  def e2 = "Hello world" must startWith("Hello")
  def e3 = "Hello world" must endWith("world")

}

Khi chạy file này, method def is=s2 sẽ được thực thi, trong method mỗi một dòng code sẽ có 1 dòng comment, các comment trong file trên sẽ là: contain 11 characters, start with 'Hello'end with 'world' chúng lần lượt là comment của các method được chạy lần lượt e1, e2 và e3. Lưu ý ký tự đặc biệt $ trước các method nhằm giúp phân biệt giữa đâu là comment và đâu là nơi chạy các method. Với một test case được viết như trên những người làm về nghiệp vụ có thể đọc và hiểu được test case này đang làm gì, mà không cần quan tâm nhiều đến code viết bằng Scala.

Trong thực tế các test case phức tạp hơn nhiều, bằng việc ném xử lý phần logic vào các method trong Scala, với cách đặt tên các method này hợp lý, có nghĩa(meaningful). Sau đó các method này sẽ được gọi kết hợp Specs2 sẽ khiến cho test case cực kỳ dễ đọc, dễ hiểu với bất cứ ai. Đó là một trong những điều quan trọng nhất khi viết test. Bởi với những project đòi hỏi thời gian maintain (lên tới 80% chi phí dự án) thì cũng kéo theo việc phải chỉnh sửa các test case liên tục. Specs2 giúp các tester và developer giảm đáng kể thời gian cho việc này

Như vậy với việc sử dụng Scala, Junit, Specs2 và Selenium bạn sẽ có thêm một sự lựa chọn tốt cho các dự án cần viết autotest cho GUI.