làm TDD với grails
groovy
5
grails
3
TDD
11
White

Li Nguyen viết ngày 12/05/2016

Hôm nay thanh niên Groovy dev này sẽ tiếp tục giới thiệu mấy thứ vui vui của Groovy.

Câu chuyện bắt đầu cách đây vài tháng lúc đấy mình vừa vào cty, có lần anh chàng leader xem qua code của mình rồi bắt đầu tỏ thái độ các kiểu như là:

Ơ sao em lại cho cái này nằm chỗ này..

Đại loại thế.

Lúc đấy mình self review lại code thì nhận ra đúng là nhiều chỗ mình cũng ko làm đúng phong cách thuần OOP lắm.

Ví dụ 1 đoạn code search tên sách trong 1 list book mình sẽ code kiểu như này:

package test

class BookController {

    static scaffold = true

    def list() {
        params.max = Math.min(params.max ? params.int('max') : 5, 50)

        def bookList = Task.createCriteria().list (params) {
            if ( params.query ) {
                ilike("description", "%${params.query}%")
            }

        [bookInstanceList: bookList, bookInstanceTotal: bookList.totalCount]
    }
}

Và vấn đề xuất hiện, đoạn query đúng ko ra được phép xuất hiện ở Controller. Đúng ra thì các business logic thường được đặt ở service hoặc domain-class (model).

Ở ví dụ này nếu move đoạn code này đi thì khá đơn giản, nhưng nó chỉ là cái ví dụ. Thực tế mình làm việc thì những đoạn logic khá phức tạp và dài loằng ngoằng. Lỡ làm lộn xộn lên thì lỗi ra cả núi, code lại thì khá tốn thời gian.

Và mình tìm được 1 plugin giúp phần lớn trong việc mình sẽ sử dụng TDD để refactor lại những chỗ sai như thế này:

plugins {
        test ":spock:0.6"
}

Đầu tiên tất nhiên là mình sẽ ngồi tạo ra đống test case.

package todo

import grails.test.mixin.*
import org.junit.*

import spock.lang.Specification
import java.awt.print.Book
import grails.plugin.spock.UnitSpec
import spock.lang.Unroll

@TestFor(Book)
class BookSpec extends Specification {

    @Unroll
    def "With query '#query', search() will return #count results!"() {
        given:
            [
                new Book(description: "Cracking the coding interview"),
                new Book(description: "Coding for interview"),
            ]*.save()

        expect:
            count == Book.search(query).count()

        where:
            count   | query
            2       | "coding"
            2       | "interview"
            1       | "Cracking"
            1       | "the"
            1       | "for"
            0       | "yolo"
    }

}

Sau đấy sẽ viết method serch() đặt trong domain class Book

class Book {  
 String description  

    static search { query ->
        }
}  

Chạy thử command để xem nó ra cái gì grails test-app com.grailstdd.BookSpec
Và kết quả hiện ra với vài case chưa pass:

com.grailstdd.BookSpec at With query 'the', search() will return 1 results! FAILED
count == Task.search(query).count()
|     |       |      |      |
0     false   |      the   1
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57

com.grailstdd.BookSpec at With query 'for', search() will return 1 results! FAILED
count == Task.search(query).count()
|     |       |      |      |
0     false   |      for   1
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:51

com.grailstdd.BookSpec at With query 'yolo', search() will return 0 results! FAILED
count == Task.search(query).count()
|     |       |      |      |
0     false   |      yolo   0
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57
    org.spockframework.runtime.ConditionNotSatisfiedError at BookSpec.groovy:57


| Completed 1 spock test, 3 failed in 1.322ms
| Tests FAILED  - view reports in target/test-reports

Mấy lỗi này hơi căn bản nhưng mình đang viết lại theo đúng trình tự những lần đầu mình làm chưa quen, vấn đề là ở function searcg() mình chưa move việc xử lý vô đây. Giờ mình sẽ chuyển phần bussiness từ Controller khi nãy qua đây.

class Book {  
 String description  

    static search { query ->
        if ( query ) {
                ilike("description", "%${query}%")
            }
        }
}  

Và giờ chạy lại test case

| Completed 1 spock test, 0 failed in 1.467 secs
| Tests PASSED - view reports in target/test-reports

Và cái Controller của mình giờ sẽ đúng hơn :D

package test

class BookController {

    static scaffold = true

    def list() {
        params.max = Math.min(params.max ? params.int('max') : 5, 50)

        def bookList = Book.search(params.query).list (params) 

        [bookInstanceList: bookList, bookInstanceTotal: bookList.totalCount]

}

Đây là 1 ví dụ nhỏ nhỏ về việc mình sử dụng TDD để refactor code trong grails thế nào.
Hy vọng càng làm sẽ tìm được mấy thứ hay hay hơn ^^

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Li Nguyen

2 bài viết.
3 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
9 0
Trước đây mình chủ yếu code Java vs PHP nhưng dạo gần đây do nhu cầu công việc nên bị bắt dùng qua Groovy và framework của nó là Grails. Groovy là...
Li Nguyen viết 2 năm trước
9 0
Bài viết liên quan
White
4 2
Một số hàm giúp mapping data đơn giản với Groovy Ví dụ với list data như sau: def student1 = name: "Huan", age: 22, gender: "male"] def student...
Tất Huân viết 3 ngày trước
4 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
2 bài viết.
3 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!