Go'da kanal ardışık düzenleri nasıl test edilir

Aug 15 2020

Go'da "kanal ardışık düzeni" modelini oldukça kullanıyorum, bu şuna benzer:

// 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)

Tekrar tekrar karşılaştığım sorun, bu boru hattı işlevlerinin bir dizi farklı özelliğini test etmem gerektiğidir:

  • Giriş kanalına bir tane koyduğunuzda çıkış kanalına bir değer koyar
  • Giriş kanalına bir değer koymadığınızda çıkış kanalına bir değer koymaz
  • Giriş kanalında bir değer göründükten sonra çıkış kanalı çok uzun sürerse zaman aşımına uğradı
  • Giriş kanalı kapandığında çıkış kanalını kapatır
  • Giriş kanalı kapanmadan çıkış kanalını kapatmaz
  • Girdi üzerinde doğru dönüşümü gerçekleştirir

Üstelik bu sadece gerçekten basit bir örnek. Daha tipik durumlar, çıktıdaki hataları bulmak için yedekli sıcaklık sensörlerini kullanmaya çalıştığımız bu örnek gibi bir şeye benziyor:

// 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 }
        }

    }
}

Şimdi, ardışık düzen işlevi ( safify) için test etmem gereken şeylerin sayısı önemli ölçüde artıyor:

  • Tüm giriş kanallarında bir tane aldığınızda çıkış kanalına bir değer koyar
  • Tüm giriş kanallarında bir tane almadığınızda çıkış kanalına bir değer koymaz
  • Çıkış kanalı, üç giriş kanalının tümünde girişlerden sonra çok uzun sürerse, ancak yalnızca üçü
  • Herhangi bir giriş kanalı kapandığında çıkış kanalını kapatır
  • Hiçbir giriş kanalı kapalı değilse çıkış kanalını kapatmaz
  • Değil Bayraklar isSafebirinci kanal zaman aşımı ile diğerlerinden önemli ölçüde farklılık gösteriyorsa
  • Değil Bayraklar isSafeikinci kanal zaman aşımı ile diğerlerinden önemli ölçüde farklılık gösteriyorsa
  • Değil Bayraklar isSafeüçüncü kanal zaman aşımı ile diğerlerinden önemli ölçüde farklılık gösteriyorsa
  • Olarak değil Bayraklar isSafeeğer bütün kanallar diğerlerinden, zaman aşımları ile önemli ölçüde değişir

Ayrıca, üç giriş kanalı birbiriyle senkronize olmayabilir, bu da yukarıda gösterilenin ötesinde önemli bir karmaşıklık ekler.

Görünüşe göre bu kontrollerin çoğu (özellikle doğru hesaplamalarla yapmak zorunda olanlar hariç) Go'daki tüm fan tarzı kanal ardışık düzeni işlevlerinde ortaktır ve Durma Sorunu herkes için zaman aşımlarını kullanmamız gerektiğini garanti eder. Testlerimizin durdurulmasının, test edilen fonksiyonların durdurulmasına ve nihai kanal itme davranışına bağlı olmasını istemediğimiz sürece, bu işlemlerden bazıları.

Bu tür testlerin pano genelinde ne kadar benzer olduğu ve nasıl oldukça benzer testler yazdığım göz önüne alındığında, temelde bu kanal boru hattı işlevlerinin , işlevlerin davranışları yerine, temel kanal işlem hattı işlev garantilerine ne kadar iyi uyduğunu tekrar tekrar test ediyorum. , ya:

  1. Bu tür kanal boru hattı işlevi güvenilirlik testleri etrafında standart bir uygulama seti VEYA
  2. Kanala özgü işlevleri test etmek için standart veya iyi güçlendirilmiş bir çerçeve veya çerçeve kümesi mi?

Yanıtlar

2 KarlBielefeldt Aug 16 2020 at 18:27

İki farklı endişeyi karıştırıyorsunuz. Ardışık düzen için ayrı bir soyutlama yaptıysanız, bunu bir kez test edebilirsiniz. Gibi bir şey (affet sözdizimi, gitmeyi bilmiyorum):

func double(v int) int {
    return v * 2
}

pipeline(in, out, double)

veya

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)

Parametrik polimorfizm olmadan, tam anlamıyla genel bir pipelinesoyutlama yapamazsınız , bu yüzden belirli bir miktarda tekrarlamayı kabul etmeniz gerekir. Bununla birlikte, en azından boru hattı modelinin endişelerini daha uygulamaya özgü mantıktan ayırabilmelisiniz.