गो में अलग इकाई परीक्षण और एकीकरण परीक्षण


97

क्या GoLang (गवाही) में यूनिट परीक्षणों और एकीकरण परीक्षणों को अलग करने के लिए एक स्थापित सर्वोत्तम अभ्यास है? मेरे पास इकाई परीक्षणों का मिश्रण है (जो किसी भी बाहरी संसाधनों पर भरोसा नहीं करते हैं और इस प्रकार वास्तव में तेजी से चलते हैं) और एकीकरण परीक्षण (जो किसी भी बाहरी संसाधनों पर भरोसा करते हैं और इस तरह धीमी गति से चलते हैं)। इसलिए, मैं यह कहना चाहता हूं कि जब मैं कहूं तो एकीकरण परीक्षण शामिल कर सकता हूं या नहीं go test

सबसे सीधी-आगे की तकनीक मुख्य रूप से एक-ध्वज को परिभाषित करने के लिए प्रतीत होगी:

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

और फिर हर एकीकरण परीक्षण के शीर्ष पर एक if-statement जोड़ने के लिए:

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

क्या यह सबसे अच्छा मैं कर सकता हूं? मैंने यह देखने के लिए गवाही दस्तावेज खोजा कि क्या कोई नामकरण सम्मेलन या कुछ ऐसा है जो मेरे लिए इसे पूरा करता है, लेकिन कुछ भी नहीं मिला। क्या मैं कुछ भूल रहा हूँ?


2
मुझे लगता है कि stdlib नेटवर्क को हिट करने वाले परीक्षणों को निष्क्रिय करने के लिए -Sort का उपयोग करता है (और अन्य दीर्घकालिक सामान भी)। अन्य वार आपका समाधान ठीक लग रहा है।
वोल्कर

-शॉर्ट एक अच्छा विकल्प है, जैसा कि आपके कस्टम बिल्ड झंडे हैं, लेकिन आपके झंडे की आवश्यकता मुख्य नहीं है। यदि आप var integration = flag.Bool("integration", true, "Enable integration testing.")किसी फ़ंक्शन के बाहर के रूप में संस्करण को परिभाषित करते हैं , तो चर पैकेज के दायरे में दिखाई देगा, और झंडा ठीक से काम करेगा
Atifm

जवाबों:


155

@ Ainar-G अलग-अलग परीक्षणों के लिए कई बेहतरीन पैटर्न सुझाता है।

साउंडक्लाउड से गो प्रथाओं का यह सेट बिल्ड टैग ( बिल्ड पैकेज के "निर्माण में बाधाएं" अनुभाग में वर्णित) का उपयोग करने के लिए सिफारिश करता है कि कौन से परीक्षण चलाने के लिए:

एक इंटीग्रेशन_test.go लिखें, और इसे एकीकरण का बिल्ड टैग दें। सर्विस एड्रेस और कनेक्टिंग स्ट्रिंग्स जैसी चीजों के लिए (वैश्विक) झंडे को परिभाषित करें और अपने परीक्षणों में उनका उपयोग करें।

// +build integration

var fooAddr = flag.String(...)

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

go test बिलकुल वैसे ही जैसे टैग बनाते हैं, वैसे ही आप कॉल कर सकते हैं go test -tags=integration। यह एक पैकेज मुख्य को भी संश्लेषित करता है, जो ध्वज को कॉल करता है। दुर्लभ, इसलिए घोषित और दिखाई देने वाले किसी भी झंडे को संसाधित किया जाएगा और आपके परीक्षणों के लिए उपलब्ध होगा।

एक समान विकल्प के रूप में, आप एक बिल्ड स्थिति का उपयोग करके डिफ़ॉल्ट रूप से चलाए जाने वाले एकीकरण परीक्षण भी कर सकते हैं // +build !unit, और फिर उन्हें चलाकर मांग पर अक्षम कर सकते हैं go test -tags=unit

@adamc टिप्पणियाँ:

बिल्ड टैग का उपयोग करने का प्रयास करने वाले किसी अन्य व्यक्ति के लिए, यह महत्वपूर्ण है कि // +build testटिप्पणी आपकी फ़ाइल में पहली पंक्ति है, और यह कि आप टिप्पणी के बाद एक रिक्त लाइन शामिल करते हैं, अन्यथा -tagsकमांड निर्देश को अनदेखा कर देगा।

इसके अलावा, बिल्ड टिप्पणी में उपयोग किए गए टैग में डैश नहीं हो सकता है, हालांकि अंडरस्कोर की अनुमति है। उदाहरण के लिए, // +build unit-testsकाम नहीं करेगा, जबकि // +build unit_testsहोगा।


1
मैं पिछले कुछ समय से इसका उपयोग कर रहा हूं और यह अब तक का सबसे तार्किक और सरल तरीका है।
ओरी बैंड

1
यदि आपके पास एक ही पैकेज में यूनिट टेस्ट हैं, तो आपको // + build unitटेस्ट चलाने के लिए यूनिट टेस्ट और यूज़ -टैग यूनिट में सेट करना होगा
LeoCBS

2
@ Tyler.z.yang क्या आप टैगों को हटाने के बारे में एक लिंक या अधिक विवरण प्रदान कर सकते हैं? मुझे ऐसी जानकारी नहीं मिली। मैं उत्तर में वर्णित तरीके के लिए go1.8 के साथ टैग का उपयोग कर रहा हूं और परीक्षणों में प्रकारों और कार्यों का मजाक उड़ाने के लिए भी। मुझे लगता है कि इंटरफेस के लिए यह अच्छा विकल्प है।
अलेक्जेंडर आई। ग्रेफोव

2
बिल्ड टैग का उपयोग करने का प्रयास करने वाले किसी अन्य व्यक्ति के लिए, यह महत्वपूर्ण है कि // +buildपरीक्षण टिप्पणी आपकी फ़ाइल में पहली पंक्ति है, और यह कि आप टिप्पणी के बाद एक रिक्त लाइन शामिल करते हैं, अन्यथा -tagsकमांड निर्देश को अनदेखा कर देगा। इसके अलावा, बिल्ड टिप्पणी में उपयोग किए गए टैग में डैश नहीं हो सकता है, हालांकि अंडरस्कोर की अनुमति है। उदाहरण के लिए, // +build unit-testsकाम नहीं करेगा, जबकि // +build unit_testsहोगा
adamc

6
कैसे संभालें वाइल्डकार्ड? go test -tags=integration ./...काम नहीं करता है, यह टैग की अनदेखी करता है
एरिका डिसूजा

53

@ Ainar जी उत्तम जवाब है, पिछले एक साल में मैं के संयोजन का उपयोग किया गया करने के लिए मेरी टिप्पणी पर विस्तार करने के लिए -shortसाथ Integrationनामकरण परिपाटी दोनों दुनिया का सबसे अच्छा प्राप्त करने के लिए।

इकाई और एकीकरण एक ही फाइल में सद्भाव का परीक्षण करता है

झंडे बिल्ड पहले मुझे मजबूर एकाधिक फ़ाइलों (के लिए services_test.go, services_integration_test.go, आदि)।

इसके बजाय, इस उदाहरण को नीचे लें जहां पहले दो यूनिट परीक्षण हैं और अंत में मेरा एकीकरण परीक्षण है:

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")
    }
    ...
}

ध्यान दें कि अंतिम परीक्षा में अधिवेशन है:

  1. Integrationपरीक्षण नाम में उपयोग करना ।
  2. अगर -shortझंडा निर्देशन के तहत चल रहा है तो जाँच ।

असल में, युक्ति यह जाती है: "सभी परीक्षण सामान्य रूप से लिखें। यदि यह लंबे समय से चल रहा परीक्षण है, या एकीकरण परीक्षण है, तो इस नामकरण सम्मेलन का पालन करें और -shortअपने साथियों के लिए अच्छा होने की जाँच करें।"

केवल यूनिट परीक्षण चलाएं:

go test -v -short

यह आपको संदेशों का एक अच्छा सेट प्रदान करता है जैसे:

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

केवल एकीकरण टेस्ट चलाएं:

go test -run Integration

यह केवल एकीकरण परीक्षण चलाता है। उत्पादन में धुएं के परीक्षण के डिब्बे के लिए उपयोगी।

जाहिर है कि इस दृष्टिकोण के लिए नकारात्मक पक्ष यह है कि अगर कोई भी झंडा के go testबिना चलता है , तो -shortवह सभी परीक्षणों - इकाई और एकीकरण परीक्षणों को चलाने के लिए डिफ़ॉल्ट होगा।

वास्तव में, यदि आपकी परियोजना इकाई और एकीकरण परीक्षणों के लिए पर्याप्त बड़ी है, तो आप सबसे अधिक संभावना है कि Makefileजहां आप go test -shortइसका उपयोग करने के लिए सरल निर्देश रख सकते हैं । या, बस इसे अपनी README.mdफ़ाइल में रखें और दिन को कॉल करें।


3
सादगी से प्यार करें
याकूब स्टेनली

क्या आप पैकेज के केवल सार्वजनिक भागों तक पहुंचने के लिए इस तरह के परीक्षण के लिए अलग पैकेज बनाते हैं? या सब मिलाया?
-31

@ डॉ। वेल, यह उत्तर से ओटी है। लेकिन व्यक्तिगत रूप से, मैं दोनों को पसंद करता हूं: परीक्षणों के लिए एक अलग पैकेज का नाम इसलिए मैं importअपना पैकेज और इसके खिलाफ परीक्षण कर सकता हूं, जो मुझे दिखाता है कि मेरा एपीआई दूसरों के लिए कैसा दिखता है। मैं तब किसी भी शेष तर्क का पालन करता हूं जिसे आंतरिक परीक्षण पैकेज नामों के रूप में कवर करने की आवश्यकता होती है।
eduncan911

@ eduncan911 उत्तर के लिए धन्यवाद! इसलिए जैसा कि मैं समझता हूं कि package servicesइसमें एक एकीकरण परीक्षण शामिल है, इसलिए APIfo को एक ब्लैकबॉक्स के रूप में पैकेज का परीक्षण करने के लिए हमें इसे दूसरे तरीके से नाम देना चाहिए, इससे package services_integration_testहमें आंतरिक संरचनाओं के साथ काम करने का मौका नहीं मिलेगा। इसलिए यूनिट टेस्ट (इंटर्नल एक्सेसिंग) के लिए पैकेज का नाम होना चाहिए package services। ऐसा है क्या?

यह सही है, हाँ। यहाँ मैं कैसे करूँ का एक साफ उदाहरण है: github.com/eduncan911/podcast (नोटिस 100% कोड कवरेज, उदाहरणों का उपयोग करके)
eduncan911

50

मैं तीन संभव समाधान देखता हूं। पहला यूनिट परीक्षणों के लिए लघु मोड का उपयोग करना है । इसलिए आप go test -shortयूनिट परीक्षणों और -shortझंडे के बिना भी अपने एकीकरण परीक्षणों को चलाने के लिए उपयोग करेंगे। मानक लाइब्रेरी शॉर्ट मोड का उपयोग या तो लंबे समय से चल रहे परीक्षणों को छोड़ने के लिए करती है, या उन्हें सरल डेटा प्रदान करके तेजी से चलाती है।

दूसरा एक कन्वेंशन का उपयोग करना और TestUnitFooया तो अपने परीक्षणों को कॉल करना है या TestIntegrationFooफिर -runपरीक्षण ध्वज का उपयोग करना है ताकि यह पता लगाया जा सके कि कौन से परीक्षण चलाने हैं। इसलिए आप go test -run 'Unit'इकाई परीक्षणों के लिए और go test -run 'Integration'एकीकरण परीक्षणों के लिए उपयोग करेंगे ।

तीसरा विकल्प एक पर्यावरण चर का उपयोग करना है, और इसे अपने परीक्षण सेटअप में प्राप्त करें os.Getenv। फिर आप go testयूनिट परीक्षणों के लिए और FOO_TEST_INTEGRATION=true go testएकीकरण परीक्षणों के लिए सरल का उपयोग करेंगे ।

मैं व्यक्तिगत रूप से -shortसमाधान को प्राथमिकता दूंगा क्योंकि यह सरल है और मानक पुस्तकालय में उपयोग किया जाता है, इसलिए ऐसा लगता है कि यह लंबे समय से चल रहे परीक्षणों को अलग / सरल बनाने का एक वास्तविक तरीका है। लेकिन -runऔर os.Getenvसमाधान अधिक लचीलेपन की पेशकश करते हैं (अधिक सावधानी की आवश्यकता होती है, क्योंकि regexps शामिल हैं -run)।


1
ध्यान दें कि सामुदायिक परीक्षण धावकों (जैसे Tester-Go) आईडीई (एटम, उदात्त, आदि) के लिए सामान्य है, -shortझंडे के साथ -coverageऔर अन्य के साथ चलाने के लिए अंतर्निहित विकल्प है । इसलिए, मैं if testing.Short()उन परीक्षणों के भीतर जांच के साथ, परीक्षण के नाम में एकीकरण के संयोजन का उपयोग करता हूं । यह मुझे दोनों दुनिया में सबसे अच्छा करने की अनुमति देता है: -shortIDEs के साथ चलाएं , और स्पष्ट रूप से केवल एकीकरण परीक्षण go test -run "Integration"
चलाएं

5

मैं हाल ही में इसके लिए एक समाधान खोजने की कोशिश कर रहा था। ये मेरे मानदंड थे:

  • समाधान सार्वभौमिक होना चाहिए
  • एकीकरण परीक्षणों के लिए कोई अलग पैकेज नहीं
  • अलगाव पूरा होना चाहिए (मुझे केवल एकीकरण परीक्षण चलाने में सक्षम होना चाहिए )
  • एकीकरण परीक्षणों के लिए कोई विशेष नामकरण सम्मेलन नहीं
  • यह अतिरिक्त टूलींग के बिना अच्छी तरह से काम करना चाहिए

उपरोक्त समाधान (कस्टम ध्वज, कस्टम बिल्ड टैग, पर्यावरण चर) वास्तव में उपरोक्त सभी मानदंडों को पूरा नहीं करते थे, इसलिए थोड़ा खुदाई और खेलने के बाद मैं इस समाधान के साथ आया:

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

कार्यान्वयन सीधा और न्यूनतम है। हालाँकि इसमें परीक्षणों के लिए एक साधारण सम्मेलन की आवश्यकता होती है, लेकिन यह कम त्रुटि वाला है। आगे सुधार एक सहायक समारोह के लिए कोड निर्यात किया जा सकता है।

प्रयोग

किसी प्रोजेक्ट में केवल सभी पैकेजों में एकीकरण परीक्षण चलाएं:

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

सभी परीक्षण चलाएं ( नियमित और एकीकरण):

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

केवल नियमित परीक्षण चलाएं :

go test -v ./...

यह समाधान टूलिंग के बिना अच्छी तरह से काम करता है, लेकिन मेकफाइल या कुछ उपनाम उपयोगकर्ता के लिए इसे आसान बना सकते हैं। इसे आसानी से किसी भी आईडीई में एकीकृत किया जा सकता है जो चलने वाले परीक्षणों का समर्थन करता है।

इसका पूरा उदाहरण यहां पाया जा सकता है: https://github.com/sagikazarmark/modern-go-application

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.