Cách kiểm tra đường ống kênh trong Go
Tôi sử dụng mô hình "đường ống kênh" khá nhiều trong Go, trông giống như sau:
// getSomeNums spits out ints onto a channel. Temperatures, pressures, doesn't matter
func getSomeNums(ch chan<- int) {
// Imagination goes here
}
// double takes numbers from in, doubles them, and pushes them into out
func double(in <-chan int, out chan<- int) {
for v := range in {
out <- v * 2
close(out)
}
source := make(chan int)
go getSomeNums(source)
doubles := make(chan int)
double(source, doubles)
Vấn đề mà tôi liên tục gặp phải, là tôi phải kiểm tra một số tính năng khác nhau của các chức năng đường ống này:
- Đặt một giá trị trên kênh đầu ra khi bạn đặt một giá trị trên kênh đầu vào
- Không đặt giá trị trên kênh đầu ra khi bạn không đặt một giá trị trên kênh đầu vào
- Hết thời gian chờ nếu kênh đầu ra mất quá nhiều thời gian sau khi giá trị xuất hiện trên kênh đầu vào
- Đóng kênh đầu ra khi kênh đầu vào đóng
- Không đóng kênh đầu ra trước khi đóng kênh đầu vào
- Thực hiện chuyển đổi chính xác trên đầu vào
Hơn nữa, đây chỉ là một ví dụ thực sự đơn giản. Các trường hợp điển hình hơn trông giống như ví dụ này, theo đó chúng tôi đang cố gắng sử dụng các cảm biến nhiệt độ dự phòng để tìm lỗi trong đầu ra:
// Provided we have channels for sensorA, sensorB, and sensorC
import "math"
LIMIT = 0.1 // Set acceptable variation limit between sensors to 10%
type SafeTemp struct {
Temp float64
isSafe bool
}
// variation returns relative error between inputs. Unfortunately, "error" was taken
func variation(a, b float64) float64 {
return math.Abs((a - b) / (a + b))
}
// safify zips together temperatures so long as error is below LIMIT
func safify(chA, chB, chC <-chan float64, chOut chan<- SafeTemp) {
for {
a, aOk := <-chA
b, bOk := <-chB
c, cOk := <-chC
if !(aOk && bOk && cOk) {
close(chOut)
return
}
if variation(a, b) < LIMIT && variation(b, c) < LIMIT &&
variation(c, a) < LIMIT {
chOut <- SafeTemp{ (a + b + c) / 3, true }
} else {
chOut <- SafeTemp{ 0.0, false }
}
}
}
Bây giờ số thứ tôi phải kiểm tra cho hàm đường ống ( safify) tăng lên đáng kể:
- Đặt một giá trị trên kênh đầu ra khi bạn nhận được một giá trị trên tất cả các kênh đầu vào
- Không đặt giá trị trên kênh đầu ra khi bạn không nhận được giá trị trên tất cả các kênh đầu vào
- Hết thời gian nếu kênh đầu ra mất quá nhiều thời gian sau khi đầu vào trên cả ba kênh đầu vào nhưng chỉ cả ba
- Đóng kênh đầu ra khi bất kỳ kênh đầu vào nào đóng lại
- Không đóng kênh đầu ra nếu không có kênh đầu vào nào được đóng
- Gắn cờ như không
isSafenếu kênh đầu tiên thay đổi đáng kể so với các kênh khác, với thời gian chờ - Gắn cờ như không
isSafenếu kênh thứ hai thay đổi đáng kể so với những kênh khác, với thời gian chờ - Gắn cờ như không
isSafenếu kênh thứ ba thay đổi đáng kể so với những kênh khác, với thời gian chờ - Gắn cờ như không
isSafenếu tất cả các kênh khác nhau đáng kể so với các kênh khác, với thời gian chờ
Hơn nữa, ba kênh đầu vào có thể không đồng bộ với nhau, điều này làm tăng thêm độ phức tạp đáng kể vẫn còn vượt quá trình bày ở trên.
Có vẻ như rất nhiều lần kiểm tra này (ngoại trừ những lần kiểm tra cụ thể phải thực hiện với tính toán chính xác) về cơ bản là phổ biến đối với bất kỳ chức năng kênh kênh kiểu người hâm mộ nào trong Go và Sự cố tạm dừng đảm bảo rằng chúng tôi phải sử dụng thời gian chờ cho tất cả của các hoạt động này, trừ khi chúng ta muốn việc tạm dừng các thử nghiệm của mình phụ thuộc vào hành vi tạm dừng và cuối cùng là đẩy kênh của các chức năng đang được thử nghiệm.
Xét về mức độ tương tự của các loại kiểm tra này trên toàn bộ diện mạo và cách tôi viết các bài kiểm tra khá giống nhau về cơ bản là kiểm tra xem các chức năng đường ống kênh này tuân theo các đảm bảo chức năng đường ống kênh cơ bản như thế nào , thay vì hành vi của các chức năng , lặp đi lặp lại , có một trong hai:
- Một bộ tiêu chuẩn thực hành xung quanh các loại kiểm tra độ tin cậy của chức năng đường ống kênh HOẶC
- Một khuôn khổ tiêu chuẩn hoặc được củng cố tốt hoặc một bộ khuôn khổ để thử nghiệm các chức năng kênh gốc?
Trả lời
Bạn đang trộn lẫn hai mối quan tâm khác nhau. Nếu bạn đã tạo một phần trừu tượng riêng cho đường ống, bạn có thể kiểm tra điều đó một lần. Một cái gì đó như (tha thứ cho cú pháp, tôi không biết đi):
func double(v int) int {
return v * 2
}
pipeline(in, out, double)
hoặc là
func safe(v [3]float64) SafeTemp {
if variation(v[0], v[1]) < LIMIT && variation(v[1], v[2]) < LIMIT &&
variation(v[2], v[0]) < LIMIT {
return SafeTemp{ (v[0] + v[1] + v[2]) / 3, true }
} else {
return SafeTemp{ 0.0, false }
}
}
pipeline(in, out, safe)
Nếu không có đa hình tham số, bạn không thể thực sự tạo ra một sự pipelinetrừu tượng hoàn toàn chung chung , vì vậy bạn phải chấp nhận một số lượng trùng lặp nhất định. Tuy nhiên, ít nhất bạn sẽ có thể tách các mối quan tâm của mô hình đường ống khỏi logic dành riêng cho ứng dụng.