2014-11-07 16 views
8

Tôi có một chức năng đơn giản, tôi muốn kiểm tra:Làm thế nào để thử nghiệm một sản lượng chức năng của (stdout/stderr) tại Gò đơn vị kiểm tra

func (t *Thing) print(min_verbosity int, message string) { 
    if t.verbosity >= minv { 
     fmt.Print(message) 
    } 
} 

Nhưng làm thế nào tôi có thể kiểm tra những gì thực tế hàm gửi tới đầu ra tiêu chuẩn? Test::Output làm những gì tôi muốn trong Perl. Tôi biết tôi có thể viết bài soạn sẵn của riêng tôi để làm điều tương tự tại Gò (như mô tả here):

orig = os.Stdout 
r,w,_ = os.Pipe() 
thing.print("Some message") 
var buf bytes.Buffer 
io.Copy(&buf, r) 
w.Close() 
os.Stdout = orig 
if(buf.String() != "Some message") { 
    t.Error("Failure!") 
} 

Nhưng đó là rất nhiều công việc bổ sung cho tất cả các thử nghiệm duy nhất. Tôi hy vọng có một cách tiêu chuẩn hơn, hoặc có thể là một thư viện trừu tượng để xử lý điều này.

Trả lời

15

Một điều cần nhớ, không có gì ngăn bạn viết các hàm để tránh bản mẫu.

Ví dụ tôi có một ứng dụng dòng lệnh có sử dụng log và tôi đã viết chức năng này:

func captureOutput(f func()) string { 
    var buf bytes.Buffer 
    log.SetOutput(&buf) 
    f() 
    log.SetOutput(os.Stderr) 
    return buf.String() 
} 

Sau đó, sử dụng nó như thế này:

output := captureOutput(func() { 
    client.RemoveCertificate("www.example.com") 
}) 
assert.Equal("removed certificate www.example.com\n", output) 

Sử dụng thư viện khẳng định này: http://godoc.org/github.com/stretchr/testify/assert.

+0

Đây có lẽ là những gì tôi sẽ làm, vì nó là một giải pháp tổng quát hơn so với được cung cấp bởi @ Ainar-G, yêu cầu tôi kiểm soát tất cả các mã có thể xuất ra một cái gì đó. – Flimzy

9

Bạn có thể thực hiện một trong hai điều. Đầu tiên là sử dụng Examples.

Gói cũng chạy và xác minh mã ví dụ. Các hàm mẫu có thể bao gồm một chú thích dòng kết thúc bắt đầu bằng "Output:" và được so sánh với đầu ra tiêu chuẩn của hàm khi các thử nghiệm được chạy. (. Việc so sánh bỏ qua ở đầu và đuôi không gian) Đây là những ví dụ về một ví dụ:

func ExampleHello() { 
     fmt.Println("hello") 
     // Output: hello 
} 

Thứ hai (và thích hợp hơn, IMO) là sử dụng chức năng giả cho IO của bạn. Trong mã của bạn, bạn cần làm:

var myPrint = fmt.Print 

func (t *Thing) print(min_verbosity int, message string) { 
    if t.verbosity >= minv { 
     myPrint(message) // N.B. 
    } 
} 

Và trong các thử nghiệm của bạn:

func init() { 
    myPrint = fakePrint // fakePrint records everything it's supposed to print. 
} 

func Test... 

Một lựa chọn khác là sử dụng fmt.Fprintf với một io.Writer đó là os.Stdout trong mã sản xuất, nhưng có thể nói bytes.Buffer trong các thử nghiệm.

+1

Ví dụ phù hợp khi bạn có đầu ra terministic và fmt.Fprint là tốt cho khi bạn có thể kiểm soát mã in (mà bạn không thể nếu nó trong một thư viện bên ngoài hoặc một cái gì đó). Tôi nghĩ hầu hết thời gian một trong những điều này sẽ đúng. Nếu có một trường hợp mà không phải là một lựa chọn đúng để đọc những gì được viết cho os.Stdout thành một chuỗi sẽ được tốt đẹp. – voutasaurus

1

Bạn có thể xem xét thêm câu lệnh trả về vào hàm của mình để trả về chuỗi thực sự được in ra.

func (t *Thing) print(min_verbosity int, message string) string { 
    if t.verbosity >= minv { 
     fmt.Print(message) 
     return message 
    } 
    return "" 
} 

Bây giờ, kiểm tra của bạn chỉ có thể kiểm tra chuỗi được trả về dựa vào chuỗi mong muốn (thay vì in ra). Có thể một chút phù hợp hơn với Phát triển theo hướng thử nghiệm (TDD).

Và, trong mã sản xuất của bạn, không có gì cần phải thay đổi, vì bạn không phải gán giá trị trả lại của hàm nếu bạn không cần.

0

Tôi yêu tất cả các nhận xét ở đây và muốn thêm giải pháp của tôi để xử lý các chức năng Print.Như bạn thấy, tôi đã thực hiện một kiểu trả về string nhưng xử lý nó là không bắt buộc như tôi gọi nó là giống như:

PrintWarning("Some warning")

chức năng tuyên bố:

var test = false 

func PrintWarning(format string, values ...interface{}) string { 
    message := fmt.Sprintf("[WARNING] " + format, values...) 

    c := color.New(color.FgYellow) 
    if !test { 
     c.Println(message) 
    } 

    return c.Sprintln(message) 
} 

khai thử nghiệm:

func TestPrintWarning(t *testing.T) { 
    test = true 
    result := PrintWarning("Testing warning") 
    assert.Equal(t, result, "[WARNING] Testing warning\n") 
} 
Các vấn đề liên quan