আমি কিছুটা ভিন্ন পদ্ধতির ব্যবহার করছি যেখানে পাবলিক স্ট্রাক্ট পদ্ধতিগুলি ইন্টারফেস প্রয়োগ করে তবে তাদের যুক্তিগুলি কেবলমাত্র ব্যক্তিগত (অপরিবর্তিত) ফাংশনগুলিকে আবৃত করার মধ্যে সীমাবদ্ধ যা এই ইন্টারফেসগুলিকে পরামিতি হিসাবে গ্রহণ করে । এটি আপনাকে গ্রানুলারিটি দেয় যা আপনাকে কার্যত কোনও নির্ভরতার উপহাস করতে হবে এবং আপনার পরীক্ষার স্যুটটির বাইরে থেকে কোনও পরিষ্কার API থাকতে হবে।
এটিকে বোঝার জন্য এটি বোঝা জরুরি যে আপনার পরীক্ষার ক্ষেত্রে অপ্রত্যাশিত পদ্ধতিতে আপনার অ্যাক্সেস রয়েছে (যেমন আপনার _test.goফাইলগুলির মধ্যে থেকে ) তাই আপনি রফতানীর পরীক্ষার পরিবর্তে সেগুলি পরীক্ষা করে নিন যার মোড়কের পাশে কোনও যুক্তি নেই।
সংক্ষিপ্তসার হিসাবে: রফতানীর পরীক্ষার পরিবর্তে আমদানি করা ফাংশনগুলি পরীক্ষা করুন!
একটি উদাহরণ তৈরি করা যাক। বলুন যে আমাদের একটি স্ল্যাক এপিআই কাঠামো রয়েছে যার দুটি পদ্ধতি রয়েছে:
- যে
SendMessageপদ্ধতিটি একটি স্ল্যাক ওয়েবহুককে একটি HTTP অনুরোধ প্রেরণ করে
SendDataSynchronouslyপদ্ধতি যা তাদের উপর স্ট্রিং iterates একটি ফালি দেওয়া এবং কলের SendMessageপ্রতি পুনরাবৃত্তির
সুতরাং SendDataSynchronouslyএইচটিটিপি অনুরোধ না করে পরীক্ষা করার জন্য প্রতিবার আমাদের উপহাস করতে হবে 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()
}
এই পদ্ধতির সম্পর্কে আমি যা পছন্দ করি তা হ'ল অপ্রত্যাশিত পদ্ধতিগুলি দেখে আপনি পরিষ্কারভাবে নির্ভর করতে পারেন তা দেখতে পাচ্ছেন। একই সাথে আপনি যে এপিআই রফতানি করেছেন তা অনেকটাই ক্লিনার এবং কম প্যারামিটারগুলি দিয়ে যেতে হবে কারণ এখানে সত্যিকারের নির্ভরতা কেবল পিতামহীন রিসিভার যা এই সমস্ত ইন্টারফেস নিজেই প্রয়োগ করে। তবুও প্রতিটি ফাংশন সম্ভাব্যভাবে এর কেবলমাত্র একটি অংশের উপর নির্ভর করে (এক, সম্ভবত দুটি ইন্টারফেস) যা রিফ্যাক্টরকে অনেক সহজ করে তোলে। আপনার কোডটি কীভাবে কেবল কার্যকারিতা স্বাক্ষরগুলি দেখে সত্যই মিলিত হয়েছে তা দেখে ভাল লাগছে, আমি মনে করি এটি গন্ধযুক্ত কোডের বিরুদ্ধে একটি শক্তিশালী সরঞ্জাম তৈরি করে।
জিনিসগুলিকে সহজ করার জন্য আমি এখানে খেলার মাঠে কোড চালানোর অনুমতি দেওয়ার জন্য সবকিছুকে একটি ফাইলে রেখেছি তবে আমি আপনাকে গিটহাবের পুরো উদাহরণটিও পরীক্ষা করে দেখার পরামর্শ দিচ্ছি, এখানে স্লাক.গো ফাইল এবং এখানে স্ল্যাক_স্টেস্ট.গো রয়েছে ।
এবং এখানে পুরো জিনিস :)