Go'da birim testleri ve entegrasyon testlerini ayırma


102

GoLang'de birim testleri ve entegrasyon testlerini ayırmak için yerleşik bir en iyi uygulama var mı (tanıklık edin)? Birim testleri (herhangi bir dış kaynağa dayanmayan ve bu nedenle gerçekten hızlı çalışan) ve entegrasyon testleri (herhangi bir dış kaynağa dayanan ve bu nedenle daha yavaş çalışan) bir karışımım var. Bu yüzden, dediğimde entegrasyon testlerinin dahil edilip edilmeyeceğini kontrol edebilmek istiyorum go test.

En basit teknik, esas olarak bir -integrate bayrağı tanımlamak gibi görünebilir:

var runIntegrationTests = flag.Bool("integration", false
    , "Run the integration tests (in addition to the unit tests)")

Ve sonra her entegrasyon testinin üstüne bir if ifadesi eklemek için:

if !*runIntegrationTests {
    this.T().Skip("To run this test, use: go test -integration")
}

Yapabileceğimin en iyisi bu mu? Belki bir adlandırma kuralı veya bunu benim için gerçekleştiren bir şey olup olmadığını görmek için tanıklık belgelerini aradım, ancak hiçbir şey bulamadım. Bir şey mi kaçırıyorum?


2
Sanırım stdlib, ağı vuran testleri (ve diğer uzun süreli işleri de) devre dışı bırakmak için -short kullanıyor. Aksi takdirde çözümünüz iyi görünüyor.
Volker

-short, özel yapım bayraklarınız gibi iyi bir seçenektir, ancak bayraklarınızın esas olması gerekmez. var integration = flag.Bool("integration", true, "Enable integration testing.")Değişkeni bir işlevin dışında tanımlarsanız, değişken paket kapsamında görünecek ve bayrak düzgün çalışacaktır
Atifm

Yanıtlar:


160

@ Ainar-G, testleri ayırmak için birkaç harika model önerir.

SoundCloud'un bu Go uygulamaları grubu, hangi testlerin çalıştırılacağını seçmek için derleme etiketlerinin ( derleme paketinin "Derleme Kısıtlamaları" bölümünde açıklanmıştır) kullanılmasını önerir :

Bir entegrasyon_test.go yazın ve ona bir entegrasyon oluşturma etiketi verin. Hizmet adresleri ve bağlantı dizeleri gibi şeyler için (global) bayraklar tanımlayın ve bunları testlerinizde kullanın.

// +build integration

var fooAddr = flag.String(...)

func TestToo(t *testing.T) {
    f, err := foo.Connect(*fooAddr)
    // ...
}

go test, arama yapabilmeniz için tıpkı go build gibi derleme etiketleri alır go test -tags=integration. Ayrıca flag.Parse'ı çağıran bir main paketi sentezler, böylece bildirilen ve görünür tüm bayraklar işlenecek ve testleriniz için kullanılabilir olacaktır.

Benzer bir seçenek olarak, bir derleme koşulu kullanarak entegrasyon testlerini varsayılan olarak çalıştırabilir // +build !unitve ardından çalıştırarak bunları isteğe bağlı olarak devre dışı bırakabilirsiniz go test -tags=unit.

@adamc yorumlar:

Derleme etiketlerini kullanmaya çalışan herhangi biri için, // +build testyorumun dosyanızın ilk satırı olması ve yorumdan sonra boş bir satır eklemeniz önemlidir , aksi takdirde -tagskomut yönergeyi yok sayacaktır.

Ayrıca, derleme yorumunda kullanılan etiketin alt çizgilere izin verilmesine rağmen bir tire işareti olamaz. Örneğin // +build unit-testsçalışmayacak, ancak // +build unit_testsçalışacak.


1
Bunu bir süredir kullanıyorum ve şu ana kadar en mantıklı ve basit yaklaşım.
Ory Band

1
Aynı pakette birim testleriniz varsa, birim testlerinde ayarlamanız // + build unitve testleri çalıştırmak için
-tag

2
@ Tyler.z.yang, etiketlerin kullanımdan kaldırılmasıyla ilgili bir bağlantı veya daha fazla ayrıntı sağlayabilir misiniz? Böyle bir bilgi bulamadım. Cevapta açıklanan yol için ve ayrıca testlerdeki türler ve işlevlerle alay etmek için go1.8 ile etiketleri kullanıyorum. Bence arayüzlere iyi bir alternatif.
Alexander I. Grafov

2
Derleme etiketlerini kullanmaya çalışan herhangi biri için, // +buildtest yorumunun dosyanızın ilk satırı olması ve yorumdan sonra boş bir satır eklemeniz önemlidir , aksi takdirde -tagskomut yönergeyi yok sayar. Ayrıca, derleme yorumunda kullanılan etiketin alt çizgilere izin verilmesine rağmen bir tire işareti olamaz. Örneğin, // +build unit-testsçalışmayacak, oysa // +build unit_testsolacak
adamc

6
Joker karakterlerle nasıl başa çıkılır? go test -tags=integration ./...çalışmıyor, etiketi yok sayıyor
Erika Dsouza

57

@ Ainar-G'nin mükemmel cevabına yaptığım yorumu detaylandırmak için, geçtiğimiz yıl boyunca her iki dünyanın da en iyisini elde etmek için adlandırma kuralı -shortile kombinasyonunu kullanıyorum Integration.

Birim ve Entegrasyon, uyumu aynı dosyada test eder

Yapı bayrakları daha önce birden fazla dosya (yapmaya zorladı services_test.go, services_integration_test.govb).

Bunun yerine, ilk ikisinin birim testleri olduğu ve sonunda bir entegrasyon testim olduğu aşağıdaki örneği alın:

package services

import "testing"

func TestServiceFunc(t *testing.T) {
    t.Parallel()
    ...
}

func TestInvalidServiceFunc3(t *testing.T) {
    t.Parallel()
    ...
}

func TestPostgresVersionIntegration(t *testing.T) {
    if testing.Short() {
        t.Skip("skipping integration test")
    }
    ...
}

Son testin şu kurallara sahip olduğuna dikkat edin:

  1. Integrationtest adında kullanarak .
  2. -shortbayrak yönergesi altında çalışıp çalışmadığını kontrol eder .

Temel olarak, teknik özellikler şöyle gider: "tüm testleri normal şekilde yazın. Uzun süren bir test veya entegrasyon testiyse, bu adlandırma kuralını izleyin ve -shortmeslektaşlarınıza iyi davranıp davranmadığınızı kontrol edin ."

Yalnızca Birim testlerini çalıştırın:

go test -v -short

bu size aşağıdaki gibi güzel mesajlar sağlar:

=== RUN   TestPostgresVersionIntegration
--- SKIP: TestPostgresVersionIntegration (0.00s)
        service_test.go:138: skipping integration test

Yalnızca Entegrasyon Testlerini Çalıştır:

go test -run Integration

Bu yalnızca entegrasyon testlerini çalıştırır. Üretimde kanaryaların duman testi için kullanışlıdır.

Açıkçası, bu yaklaşımın dezavantajı go test, herhangi biri -shortbayrak olmadan çalıştırılırsa , varsayılan olarak tüm testleri - birim ve entegrasyon testlerini - çalıştıracak olmasıdır.

Gerçekte, projeniz birim ve entegrasyon testlerine sahip olacak kadar büyükse, büyük olasılıkla, içinde kullanmak için Makefilebasit direktiflere sahip olabileceğiniz bir yer kullanıyorsunuzdur go test -short. Ya da README.mddosyanıza koyun ve o gün çağırın.


3
sadeliği seviyorum
Jacob Stanley

Paketin yalnızca genel bölümlerine erişmek için böyle bir test için ayrı bir paket oluşturuyor musunuz? Yoksa hepsi karışık mı?
Dr.eel

@ Dr.eel Eh, cevaptan OT bu. Ancak şahsen, her ikisini de tercih ediyorum: testler için farklı bir paket adı, böylece importpaketimi yapabilir ve ona karşı test edebilirim , bu da bana API'min başkalarına nasıl göründüğünü gösterir. Ardından, dahili test paketi adları olarak kapsanması gereken kalan mantığı takip ederim.
eduncan911

@ eduncan911 Cevabınız için teşekkürler! Burada anladığım kadarıyla package servicesbir entegrasyon testi sute'si içeriyor, bu yüzden APIfo'yu bir kara kutu olarak test etmek için onu başka bir şekilde package services_integration_testadlandırmalıyız, bu bize iç yapılarla çalışma şansı vermeyecek. Bu nedenle, birim testleri için paket (dahililere erişim) adlandırılmalıdır package services. Öyle mi?
Dr.eel

Bu doğru, evet. İşte bunu nasıl yaptığıma dair net bir örnek: github.com/eduncan911/podcast (Örnekler kullanarak% 100 kod kapsamına dikkat edin)
eduncan911

51

Üç olası çözüm görüyorum. Birincisi, birim testleri için kısa modu kullanmaktır . Bu nedenle go test -short, birim testleri ve aynısını kullanırsınız, ancak -shortentegrasyon testlerinizi de çalıştırmak için bayrak olmadan kullanırsınız. Standart kitaplık, uzun süreli testleri atlamak veya daha basit veriler sağlayarak bunların daha hızlı çalışmasını sağlamak için kısa modu kullanır.

İkincisi, bir kural kullanmak ve testlerinizi ya TestUnitFooda çağırmak TestIntegrationFoove ardından hangi testlerin çalıştırılacağını belirtmek için -runtest bayrağını kullanmaktır . Yani go test -run 'Unit'birim testleri ve go test -run 'Integration'entegrasyon testleri için kullanırsınız.

Üçüncü seçenek, bir ortam değişkeni kullanmak ve bunu ile test kurulumunuza almaktır os.Getenv. O zaman go testbirim testleri ve FOO_TEST_INTEGRATION=true go testentegrasyon testleri için basit kullanırsınız .

Ben şahsen -shortçözümü daha basit olduğu ve standart kitaplıkta kullanıldığı için tercih ederim , bu yüzden uzun süreli testleri ayırmanın / basitleştirmenin fiili bir yolu gibi görünüyor. Ancak -runve os.Getenvçözümleri daha fazla esneklik sunar (normal ifadeler de dahil olduğu için daha fazla dikkat gerekir -run).


1
Tester-GoIDE'lerde (Atom, Sublime, vb.) ortak olan topluluk testi koşucularının (örneğin ) -shortbayrakla, -coverageve diğerleriyle birlikte çalıştırma yerleşik seçeneğine sahip olduğuna dikkat edin . bu nedenle, if testing.Short()bu testler içindeki kontrollerle birlikte test adında her iki Entegrasyonun bir kombinasyonunu kullanıyorum . her iki dünyanın da en iyisine sahip olmamı sağlıyor: -shortgo test -run "Integration"
IDE'lerle

5

Ben de son zamanlarda buna bir çözüm bulmaya çalışıyordum. Kriterlerim şunlardı:

  • Çözüm evrensel olmalı
  • Entegrasyon testleri için ayrı paket yok
  • Ayırma tamamlanmış olmalıdır ( yalnızca entegrasyon testlerini çalıştırabilmeliyim )
  • Entegrasyon testleri için özel bir adlandırma kuralı yok
  • Ek aletler olmadan iyi çalışmalıdır

Yukarıda belirtilen çözümler (özel bayrak, özel yapı etiketi, ortam değişkenleri) yukarıdaki kriterlerin hepsini gerçekten karşılamadı, bu yüzden biraz kazma ve oynamadan sonra şu çözümü buldum:

package main

import (
    "flag"
    "regexp"
    "testing"
)

func TestIntegration(t *testing.T) {
    if m := flag.Lookup("test.run").Value.String(); m == "" || !regexp.MustCompile(m).MatchString(t.Name()) {
        t.Skip("skipping as execution was not requested explicitly using go test -run")
    }

    t.Parallel()

    t.Run("HelloWorld", testHelloWorld)
    t.Run("SayHello", testSayHello)
}

Uygulama basit ve minimumdur. Testler için basit bir kural gerektirmesine rağmen, hataya daha az meyillidir. Daha fazla gelişme, kodu bir yardımcı işleve aktarmak olabilir.

Kullanım

Entegrasyon testlerini yalnızca bir projedeki tüm paketlerde çalıştırın:

go test -v ./... -run ^TestIntegration$

Tüm testleri çalıştırın ( normal ve entegrasyon):

go test -v ./... -run .\*

Yalnızca düzenli testler çalıştırın :

go test -v ./...

Bu çözüm, alet kullanmadan iyi çalışır, ancak bir Makefile veya bazı takma adlar kullanıcının işini kolaylaştırabilir. Ayrıca, go testleri çalıştırmayı destekleyen herhangi bir IDE'ye kolayca entegre edilebilir.

Tam örnek burada bulunabilir: https://github.com/sagikazarmark/modern-go-application

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.