मैं थोड़ा अलग दृष्टिकोण का उपयोग कर रहा हूं जहां सार्वजनिक संरचना विधियां इंटरफेस को लागू करती हैं, लेकिन उनका तर्क केवल निजी (अस्पष्टीकृत) कार्यों को लपेटने तक सीमित है जो उन इंटरफेस को मापदंडों के रूप में लेते हैं । यह आपको वह ग्रैन्युलैरिटी देता है जिसकी आपको वस्तुतः किसी भी निर्भरता का मजाक उड़ाने की आवश्यकता होगी और फिर भी आपके टेस्ट सूट के बाहर से उपयोग करने के लिए एक साफ एपीआई होना चाहिए।
इसे समझने के लिए यह समझना अत्यावश्यक है कि आपके पास आपके परीक्षण मामले (यानी आपकी _test.goफाइलों के भीतर से ) में गैर-पंजीकृत तरीकों तक पहुंच है, इसलिए आप निर्यात किए गए लोगों का परीक्षण करने के बजाय उन लोगों का परीक्षण करते हैं जिनके पास लपेटने के अंदर कोई तर्क नहीं है।
सारांशित करने के लिए: निर्यात किए गए लोगों के परीक्षण के बजाय अस्पष्टीकृत कार्यों का परीक्षण करें!
आइए एक उदाहरण बनाते हैं। कहें कि हमारे पास एक सुस्त एपीआई संरचना है जिसमें दो तरीके हैं:
- वह
SendMessageतरीका जो एक HTTP अनुरोध को स्लैक वेबहुक पर भेजता है
- जिस
SendDataSynchronouslyपद्धति ने तार का एक टुकड़ा दिया, वह उनके ऊपर SendMessageपुनरावृत्त करता है और प्रत्येक पुनरावृत्ति के लिए कहता है
तो SendDataSynchronouslyहर बार हमें HTTP अनुरोध किए बिना परीक्षण करने के लिए हमें SendMessageसही, सही करना होगा?
package main
import (
"fmt"
)
// URI interface
type URI interface {
GetURL() string
}
// MessageSender interface
type MessageSender interface {
SendMessage(message string) error
}
// This one is the "object" that our users will call to use this package functionalities
type API struct {
baseURL string
endpoint string
}
// Here we make API implement implicitly the URI interface
func (api *API) GetURL() string {
return api.baseURL + api.endpoint
}
// Here we make API implement implicitly the MessageSender interface
// Again we're just WRAPPING the sendMessage function here, nothing fancy
func (api *API) SendMessage(message string) error {
return sendMessage(api, message)
}
// We want to test this method but it calls SendMessage which makes a real HTTP request!
// Again we're just WRAPPING the sendDataSynchronously function here, nothing fancy
func (api *API) SendDataSynchronously(data []string) error {
return sendDataSynchronously(api, data)
}
// this would make a real HTTP request
func sendMessage(uri URI, message string) error {
fmt.Println("This function won't get called because we will mock it")
return nil
}
// this is the function we want to test :)
func sendDataSynchronously(sender MessageSender, data []string) error {
for _, text := range data {
err := sender.SendMessage(text)
if err != nil {
return err
}
}
return nil
}
// TEST CASE BELOW
// Here's our mock which just contains some variables that will be filled for running assertions on them later on
type mockedSender struct {
err error
messages []string
}
// We make our mock implement the MessageSender interface so we can test sendDataSynchronously
func (sender *mockedSender) SendMessage(message string) error {
// let's store all received messages for later assertions
sender.messages = append(sender.messages, message)
return sender.err // return error for later assertions
}
func TestSendsAllMessagesSynchronously() {
mockedMessages := make([]string, 0)
sender := mockedSender{nil, mockedMessages}
messagesToSend := []string{"one", "two", "three"}
err := sendDataSynchronously(&sender, messagesToSend)
if err == nil {
fmt.Println("All good here we expect the error to be nil:", err)
}
expectedMessages := fmt.Sprintf("%v", messagesToSend)
actualMessages := fmt.Sprintf("%v", sender.messages)
if expectedMessages == actualMessages {
fmt.Println("Actual messages are as expected:", actualMessages)
}
}
func main() {
TestSendsAllMessagesSynchronously()
}
इस दृष्टिकोण के बारे में मुझे जो पसंद है वह यह है कि गैर-सूचीबद्ध तरीकों को देखकर आप स्पष्ट रूप से देख सकते हैं कि निर्भरताएं क्या हैं। एक ही समय में आपके द्वारा निर्यात किया जाने वाला एपीआई एक बहुत ही साफ-सुथरा और कम मापदंडों के साथ गुजरता है क्योंकि सच्ची निर्भरता यहां सिर्फ मूल रिसीवर है जो उन सभी इंटरफेस को लागू कर रहा है। फिर भी प्रत्येक फ़ंक्शन संभावित रूप से केवल इसके एक भाग (एक, शायद दो इंटरफेस) पर निर्भर करता है जो रिफैक्टर्स को बहुत आसान बनाता है। यह देखना अच्छा है कि फ़ंक्शंस हस्ताक्षरों को देखकर आपका कोड वास्तव में कैसे युग्मित होता है, मुझे लगता है कि यह महक कोड के खिलाफ एक शक्तिशाली उपकरण बनाता है।
चीजों को आसान बनाने के लिए मैंने आपको एक फ़ाइल में सब कुछ डाल दिया, ताकि आप यहां खेल के मैदान में कोड को चला सकें, लेकिन मेरा सुझाव है कि आप GitHub पर पूरा उदाहरण देखें, यहाँ slack.go फ़ाइल है और यहाँ slack_test.go है ।
और यहाँ पूरी बात :)