मैं गो में परीक्षण पैकेज का उपयोग करके परीक्षण सेटअप कैसे कर सकता हूं


111

मैं समग्र परीक्षण सेटअप प्रसंस्करण कैसे कर सकता हूं जो परीक्षण पैकेज का उपयोग करते समय सभी परीक्षणों के लिए चरण निर्धारित करता है ?

नुनिट में एक उदाहरण के रूप में एक [SetUp]विशेषता है।

[TestFixture]
public class SuccessTests
{
  [SetUp] public void Init()
  { /* Load test data */ }
}

जवाबों:


159

गो 1.4 से शुरू करके आप सेटअप / टैडडाउन लागू कर सकते हैं (प्रत्येक परीक्षण से पहले / बाद में अपने कार्यों को कॉपी करने की आवश्यकता नहीं है)। दस्तावेज़ को मुख्य भाग में यहाँ उल्लिखित किया गया है :

TestMain मुख्य गोरोइन में चलता है और m.Run के लिए कॉल के आसपास जो भी सेटअप और अशांति आवश्यक है वह कर सकता है। इसके बाद m.un के परिणाम के साथ os.Exit को कॉल करें

मुझे यह पता लगाने में कुछ समय लगा कि इसका मतलब है कि यदि किसी परीक्षण में कोई फ़ंक्शन है func TestMain(m *testing.M)तो परीक्षण चलाने के बजाय इस फ़ंक्शन को बुलाया जाएगा। और इस फ़ंक्शन में मैं यह परिभाषित कर सकता हूं कि परीक्षण कैसे चलेंगे। उदाहरण के लिए मैं वैश्विक सेटअप और अशांति लागू कर सकता हूं:

func TestMain(m *testing.M) {
    setup()
    code := m.Run() 
    shutdown()
    os.Exit(code)
}

कुछ अन्य उदाहरण यहां दिए जा सकते हैं

नवीनतम रिलीज में गो के परीक्षण ढांचे में जोड़ा गया टेस्टमैन फीचर कई परीक्षण उपयोग मामलों के लिए एक सरल समाधान है। TestMain सेटअप और शटडाउन करने के लिए एक वैश्विक हुक प्रदान करता है, परीक्षण वातावरण को नियंत्रित करता है, एक बच्चे की प्रक्रिया में विभिन्न कोड चलाता है, या परीक्षण कोड द्वारा लीक संसाधनों के लिए जांच करता है। अधिकांश पैकेजों को टेस्टमैन की आवश्यकता नहीं होगी, लेकिन यह उन समय के लिए एक स्वागत योग्य है जब इसकी आवश्यकता होती है।


17
TestMainएक बार एक पैकेज में है, इसलिए यह उतना उपयोगी नहीं है। मुझे लगता है कि अधिक जटिल उद्देश्यों के लिए उप - योग बेहतर हैं।
इनक गमूस

3
वैश्विक चर का उपयोग किए बिना आपको सेटअप फ़ंक्शन से परीक्षण तक संदर्भ कैसे पारित करना चाहिए? उदाहरण के लिए यदि mySetupFunction () एक अद्वितीय, यादृच्छिक नाम के साथ परीक्षण करने के लिए एक अस्थायी निर्देशिका बनाता है, तो परीक्षण निर्देशिका के नाम को कैसे जानते हैं? इस संदर्भ को स्थापित करने के लिए एक जगह होनी चाहिए ??
लेक्वेर्विग

1
ऐसा लगता है कि परीक्षण के लिए हुक से पहले और बाद में इसे संभालने का आधिकारिक तरीका है, golang.org/pkg/testing/#hdr-Main को आधिकारिक दस्तावेज के लिए देखें
de-jcup

4
@ इनकंगमसlstat $GOROOT/subtests: no such file or directory
030

1
कृपया ध्यान दें कि 'कोड: = m.Run ()' वह है जो अन्य TestFunctions चलाता है!
एलेक्स पुन्नन

49

इसे फाइल init()में फंक्शन डालकर हासिल किया जा सकता है _test.go। इसे init()फंक्शन से पहले चलाया जाएगा ।

// package_test.go
package main

func init() {
     /* load test data */
}

_Test.init () पैकेज इनिट () फ़ंक्शन से पहले बुलाया जाएगा।


2
मुझे पता है कि आप अपने स्वयं के प्रश्न का उत्तर दे रहे हैं, इसलिए यह संभवतः आपके स्वयं के उपयोग के मामले को संतुष्ट करता है, लेकिन यह आपके प्रश्न में शामिल NUnit उदाहरण के बराबर नहीं है।
जेम्स हेनस्ट्रिज

खैर @james, मैंने इस मुद्दे का जवाब देने के तरीके पर एक विचार दिखाया है और दूसरों ने पहले ही कुछ अच्छी अंतर्दृष्टि प्रदान की है, जिसमें आपका भी शामिल है। लोगों के दृष्टिकोण को प्रभावित करने के लिए इसका बाहरी प्रभाव प्राप्त करना उपयोगी है। धन्यवाद।
मिल्टनब

2
काफी उचित। इस उत्तर में आपने जो दिखाया है, वह [TestFixtureSetUp]इसके बजाय NUnit की विशेषता का उपयोग करने के कुछ हद तक करीब है ।
जेम्स हेनस्ट्रिज

2
इसमें आंसू नीचे का हिस्सा शामिल नहीं है
तारास मत्स्य

7
यह एक अच्छा समाधान नहीं है यदि आपकी परीक्षण फ़ाइल मुख्य फ़ंक्शन के साथ एक ही पैकेज में है।
माउसवांटेड

28

इकाई परीक्षण के लिए एक सरल कार्य को देखते हुए:

package math

func Sum(a, b int) int {
    return a + b
}

आप इसे एक सेटअप फ़ंक्शन के साथ टेस्ट कर सकते हैं जो अश्रु फ़ंक्शन देता है। और कॉलिंग सेटअप () के बाद आप टियरडाउन () में आस्थगित कॉल कर सकते हैं।

package math

import "testing"

func setupTestCase(t *testing.T) func(t *testing.T) {
    t.Log("setup test case")
    return func(t *testing.T) {
        t.Log("teardown test case")
    }
}

func setupSubTest(t *testing.T) func(t *testing.T) {
    t.Log("setup sub test")
    return func(t *testing.T) {
        t.Log("teardown sub test")
    }
}

func TestAddition(t *testing.T) {
    cases := []struct {
        name     string
        a        int
        b        int
        expected int
    }{
        {"add", 2, 2, 4},
        {"minus", 0, -2, -2},
        {"zero", 0, 0, 0},
    }

    teardownTestCase := setupTestCase(t)
    defer teardownTestCase(t)

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            teardownSubTest := setupSubTest(t)
            defer teardownSubTest(t)

            result := Sum(tc.a, tc.b)
            if result != tc.expected {
                t.Fatalf("expected sum %v, but got %v", tc.expected, result)
            }
        })
    }
}

गो टेस्टिंग टूल शेल कंसोल में लॉगिंग स्टेटमेंट की रिपोर्ट करेगा:

% go test -v
=== RUN   TestAddition
=== RUN   TestAddition/add
=== RUN   TestAddition/minus
=== RUN   TestAddition/zero
--- PASS: TestAddition (0.00s)
    math_test.go:6: setup test case
    --- PASS: TestAddition/add (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/minus (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/zero (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    math_test.go:8: teardown test case
PASS
ok      github.com/kare/go-unit-test-setup-teardown 0.010s
% 

आप इस दृष्टिकोण के साथ सेटअप / फाड़ के लिए कुछ अतिरिक्त पैरामीटर पास कर सकते हैं।


2
अब यह एक वास्तविक सरल लेकिन प्रभावी ट्रिक है। गो सिंटैक्स का शानदार उपयोग।
मिल्टनब

1
हाँ, लेकिन यह नेस्टेडनेस ( जावास्क्रिप्ट में कयामत के पिरामिड का प्रकार) को बढ़ाता है । और, परीक्षण बाहरी परीक्षण की तरह स्वचालित रूप से सुइट द्वारा नहीं चलते हैं।
इनक गमूस

12

आमतौर पर, जाने वाले परीक्षण अन्य भाषाओं की तरह ही शैली में नहीं लिखे जाते हैं। अक्सर, अपेक्षाकृत कम परीक्षण कार्य होते हैं, लेकिन प्रत्येक में परीक्षण मामलों का एक टेबल-संचालित सेट होता है। देखें इस लेख पर जाएं टीम में से एक ने लिखा है।

टेबल-संचालित परीक्षण के साथ, आप बस किसी भी सेटअप कोड को लूप से पहले रख सकते हैं जो तालिका में निर्दिष्ट व्यक्तिगत परीक्षण-मामलों को निष्पादित करता है, और बाद में कोई भी सफाई कोड डालता है।

यदि आपने अभी भी परीक्षण कार्यों के बीच सेटअप कोड साझा किया है, तो आप किसी फ़ंक्शन में साझा सेटअप कोड को निकाल सकते हैं, और sync.Onceयदि यह महत्वपूर्ण है कि इसका उपयोग एक बार किया जाए (या किसी अन्य उत्तर से पता चलता है, उपयोग करें init(), लेकिन इसका नुकसान यह है कि सेटअप तब भी किया जाएगा जब परीक्षण के मामले नहीं चलते हैं (शायद इसलिए कि आपने परीक्षण मामलों को सीमित करके उपयोग किया है go test -run <regexp>।)

मैं कहूंगा कि यदि आपको लगता है कि आपको अलग-अलग परीक्षणों के बीच साझा सेटअप की आवश्यकता है जो कि एक बार निष्पादित हो जाए, तो आपको एक बार यह सोचना चाहिए कि क्या आपको वास्तव में इसकी आवश्यकता है, और यदि टेबल-संचालित परीक्षण बेहतर नहीं होगा।


6
यह बहुत अच्छा है जब तुच्छ चीजों का परीक्षण करते हैं जैसे कि फ्लैग पार्सर, या एक एल्गोरिथ्म जो संख्याओं पर मंथन करता है। लेकिन यह वास्तव में मदद नहीं करता है जब कार्यक्षमता के विभिन्न टुकड़ों का परीक्षण करने की कोशिश कर रहा है कि सभी को समान बॉयलरप्लेट कोड की आवश्यकता होती है। मुझे लगता है कि मैं एक सरणी में अपने परीक्षण कार्यों को परिभाषित कर सकता हूं और उन पर पुनरावृति कर सकता हूं, लेकिन फिर यह वास्तव में तालिका-संचालित नहीं है एक साधारण लूप के रूप में जो वास्तव में सिर्फ परीक्षण ढांचे में ही बनाया जाना चाहिए (उचित परीक्षण सूट के रूप में) सेटअप /
फाड़

9

गो परीक्षण ढांचे में NUnit के SetUp विशेषता के बराबर कुछ भी नहीं है (सूट में प्रत्येक परीक्षण से पहले बुलाया जाने वाला फ़ंक्शन चिह्नित करना)। हालांकि कुछ विकल्प हैं:

  1. बस SetUpप्रत्येक परीक्षण से अपने फ़ंक्शन को कॉल करें जहां इसकी आवश्यकता है।

  2. जा के परीक्षण ढांचे के विस्तार के लिए उपयोग करें जो xUnit प्रतिमान और अवधारणाओं को लागू करता है। तीन मजबूत विकल्प दिमाग में आते हैं:

इन पुस्तकालयों में से प्रत्येक आपको अपने परीक्षणों को अन्य एक्सयूनाइट फ्रेमवर्क के समान सूट / फिक्स्चर में व्यवस्थित करने के लिए प्रोत्साहित करता है, और प्रत्येक Test*विधि से पहले सूट / स्थिरता प्रकार पर सेटअप विधियों को कॉल करेगा ।


0

बेशर्म प्लग, मैंने इस समस्या को हल करने में मदद करने के लिए https://github.com/houqp/gtest बनाया ।

यहाँ एक त्वरित उदाहरण है:

import (
  "strings"
  "testing"
  "github.com/houqp/gtest"
)

type SampleTests struct{}

// Setup and Teardown are invoked per test group run
func (s *SampleTests) Setup(t *testing.T)      {}
func (s *SampleTests) Teardown(t *testing.T)   {}
// BeforeEach and AfterEach are invoked per test run
func (s *SampleTests) BeforeEach(t *testing.T) {}
func (s *SampleTests) AfterEach(t *testing.T)  {}

func (s *SampleTests) SubTestCompare(t *testing.T) {
  if 1 != 1 {
    t.FailNow()
  }
}

func (s *SampleTests) SubTestCheckPrefix(t *testing.T) {
  if !strings.HasPrefix("abc", "ab") {
    t.FailNow()
  }
}

func TestSampleTests(t *testing.T) {
  gtest.RunSubTests(t, &SampleTests{})
}

आप सेटअप / अशरण दिनचर्या के एक अलग सेट का उपयोग करके उनमें से प्रत्येक के साथ एक पैकेज के भीतर जितने भी परीक्षण समूह चाहें बना सकते हैं।

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