গোতে মক ফাংশন


147

আমি একটি ছোট ব্যক্তিগত প্রকল্প কোডিং করে গো শিখছি। এটি ছোট হলেও, শুরু থেকেই গোতে ভাল অভ্যাসগুলি শিখতে কঠোর ইউনিট পরীক্ষা করার সিদ্ধান্ত নিয়েছি।

তুচ্ছ ইউনিট পরীক্ষাগুলি সবই ভাল এবং জঘন্য ছিল, তবে আমি এখন নির্ভরতা নিয়ে আশ্চর্য হয়েছি; আমি কিছু ফাংশন কলকে মোকগুলির সাথে প্রতিস্থাপন করতে সক্ষম হতে চাই এখানে আমার কোডের একটি স্নিপেট রয়েছে:

func get_page(url string) string {
    get_dl_slot(url)
    defer free_dl_slot(url)

    resp, err := http.Get(url)
    if err != nil { return "" }
    defer resp.Body.Close()

    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil { return "" }
    return string(contents)
}

func downloader() {
    dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
    content := get_page(BASE_URL)
    links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
    matches := links_regexp.FindAllStringSubmatch(content, -1)
    for _, match := range matches{
        go serie_dl(match[1], match[2])
    }
}

আমি আসলে http এর মাধ্যমে কোনও পৃষ্ঠা না পেয়েই ডাউনলোডার () পরীক্ষা করতে সক্ষম হতে চাই - অর্থাত্ গেট_পেজ (যেহেতু এটি কেবল পৃষ্ঠার সামগ্রীটিকে স্ট্রিং হিসাবে ফিরিয়ে দেয়) তামাশা করে বা http.Get () এর মাধ্যমে উপহাস করে।

আমি এই থ্রেডটি পেয়েছি: https://groups.google.com/forum/#!topic/golang-nuts/6AN1E2CJOxI যা একই ধরণের সমস্যা বলে মনে হচ্ছে। জুলিয়ান ফিলিপস তার লাইব্রেরি, উইন্ডমক ( http://github.com/qur/withmock ) একটি সমাধান হিসাবে উপস্থাপন করেছেন , তবে আমি এটি কার্যকর করতে পারিনি। এখানে আমার টেস্টিং কোডের প্রাসঙ্গিক অংশগুলি রয়েছে, যা আমার কাছে বেশিরভাগ ক্ষেত্রে কার্গো কাল্ট কোড honest

import (
    "testing"
    "net/http" // mock
    "code.google.com/p/gomock"
)
...
func TestDownloader (t *testing.T) {
    ctrl := gomock.NewController()
    defer ctrl.Finish()
    http.MOCK().SetController(ctrl)
    http.EXPECT().Get(BASE_URL)
    downloader()
    // The rest to be written
}

পরীক্ষার ফলাফলটি নিম্নলিখিত:

ERROR: Failed to install '_et/http': exit status 1
output:
can't load package: package _et/http: found packages http (chunked.go) and main (main_mock.go) in /var/folders/z9/ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http

উইন্ডমক কি আমার পরীক্ষার সমস্যার সমাধান? এটির কাজ পেতে আমার কী করা উচিত?


যেহেতু আপনি গো ইউনিট পরীক্ষায় ডাইভিং করছেন, আচরণ-চালিত পরীক্ষা করার দুর্দান্ত উপায়ের জন্য গোকনভিতে সন্ধান করুন ... এবং টিজার: একটি স্বয়ংক্রিয়ভাবে আপডেট হওয়া ওয়েব ইউআই আসছে যা দেশী "গো পরীক্ষা" পরীক্ষার সাথেও কাজ করে।
ম্যাট

উত্তর:


193

ভাল পরীক্ষা অনুশীলনের জন্য আপনাকে কুডোস! :)

ব্যক্তিগতভাবে, আমি ব্যবহার করি না gomock(বা বিষয়টির জন্য কোনও উপহাসের কাঠামো; এটি ছাড়া গোতে মশকরা খুব সহজ)। আমি হয় downloader()প্যারামিটার হিসাবে ফাংশনের উপর নির্ভরতা পাস করব, বা আমি downloader()কোনও প্রকারে একটি পদ্ধতি তৈরি করব এবং টাইপটি get_pageনির্ভরতা ধরে রাখতে পারে :

পদ্ধতি 1: এর get_page()প্যারামিটার হিসাবে পাস করুনdownloader()

type PageGetter func(url string) string

func downloader(pageGetterFunc PageGetter) {
    // ...
    content := pageGetterFunc(BASE_URL)
    // ...
}

প্রধান:

func get_page(url string) string { /* ... */ }

func main() {
    downloader(get_page)
}

টেস্ট:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader(t *testing.T) {
    downloader(mock_get_page)
}

download()পদ্ধতি 2: একটি ধরণের পদ্ধতি তৈরি করুন Downloader:

আপনি যদি প্যারামিটার হিসাবে নির্ভরতাটি পাস করতে না চান তবে আপনি get_page()কোনও প্রকারের সদস্যও তৈরি করতে পারেন এবং download()সেই ধরণের একটি পদ্ধতি তৈরি করতে পারেন, যা পরে ব্যবহার করতে পারে get_page:

type PageGetter func(url string) string

type Downloader struct {
    get_page PageGetter
}

func NewDownloader(pg PageGetter) *Downloader {
    return &Downloader{get_page: pg}
}

func (d *Downloader) download() {
    //...
    content := d.get_page(BASE_URL)
    //...
}

প্রধান:

func get_page(url string) string { /* ... */ }

func main() {
    d := NewDownloader(get_page)
    d.download()
}

টেস্ট:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader() {
    d := NewDownloader(mock_get_page)
    d.download()
}

4
অনেক ধন্যবাদ! আমি দ্বিতীয়টির সাথে গেলাম। (এখানে অন্যান্য কিছু ফাংশন ছিল যা আমি উপহাস করতে চেয়েছিলাম, সুতরাং এগুলি কোনও স্ট্রাক্টে নির্ধারণ করা সহজ ছিল) বিটিডব্লিউ। আমি গো কিছুটা ভালবাসি। বিশেষত এর সম্মতিযুক্ত বৈশিষ্ট্যগুলি ঝরঝরে!
গোলড্র্যাঙ্কস

149
আমি কি কেবলমাত্র খুঁজে পাচ্ছি যে পরীক্ষার স্বার্থে আমাদের মূল কোড / ফাংশনগুলির স্বাক্ষরটি ভয়ানক পরিবর্তন করতে হবে?
থমাস

41
@ থমাস আমি নিশ্চিত নই যে আপনিই একমাত্র, তবে এটি প্রকৃতপক্ষে পরীক্ষা চালিত বিকাশের মৌলিক কারণ - আপনার পরীক্ষার মাধ্যমে আপনি আপনার উত্পাদন কোডটি কীভাবে লেখেন তা পরিচালনা করে। পরীক্ষারযোগ্য কোডটি আরও মডিউলার। এই ক্ষেত্রে, ডাউনলোডার অবজেক্টের 'get_page' আচরণটি এখন প্লাগযোগ্য - আমরা গতিশীলভাবে এর বাস্তবায়নটি পরিবর্তন করতে পারি। আপনাকে কেবলমাত্র আপনার মূল কোডটি পরিবর্তন করতে হবে যদি এটি প্রথমে খারাপভাবে লেখা থাকে।
weberc2

21
@ থমাস আমি আপনার দ্বিতীয় বাক্যটি বুঝতে পারি না। টিডিডি আরও ভাল কোড চালায়। আপনার কোডটি টেস্টযোগ্য হওয়ার জন্য পরিবর্তিত হয় (কারণ পরীক্ষারযোগ্য কোডটি সুচিন্তিত ইন্টারফেসগুলির সাথে প্রয়োজনীয়ভাবে মডিউলার হয়) তবে প্রাথমিক উদ্দেশ্যটি আরও ভাল কোডের হয় - স্বয়ংক্রিয় পরীক্ষাগুলি করা কেবল একটি দুর্দান্ত উপায় secondary যদি আপনার উদ্বেগের বিষয়টি হল যে সত্যের পরে পরীক্ষাগুলি যুক্ত করার জন্য ফাংশনাল কোডটি সহজেই পরিবর্তন করা হচ্ছে, তবে আমি কেবল এটির পরিবর্তনের সুপারিশ করব কারণ কোনও দিন কোনও ব্যক্তি সেই কোডটি পড়তে বা এটি পরিবর্তন করতে চান এমন সম্ভাবনা রয়েছে।
weberc2

6
@ থমাস অবশ্যই, আপনি বরাবর যাওয়ার সাথে সাথে যদি আপনার পরীক্ষাগুলি লিখছেন তবে আপনাকে সেই ঝাঁকুনির মোকাবেলা করতে হবে না।
weberc2

24

পরিবর্তে ভেরিয়েবলটি ব্যবহার করতে যদি আপনি আপনার ফাংশন সংজ্ঞা পরিবর্তন করেন:

var get_page = func(url string) string {
    ...
}

আপনি এটি আপনার পরীক্ষাগুলিতে ওভাররাইড করতে পারেন:

func TestDownloader(t *testing.T) {
    get_page = func(url string) string {
        if url != "expected" {
            t.Fatal("good message")
        }
        return "something"
    }
    downloader()
}

সতর্কতা অবলম্বন করুন, যদি আপনার ওভাররাইড করা ফাংশনটির কার্যকারিতা পরীক্ষা করে তবে আপনার অন্যান্য পরীক্ষাগুলি ব্যর্থ হতে পারে!

জিনিসগুলি পরীক্ষার সহজ করার জন্য কোড লেখকগণ কোডের মধ্যে পরীক্ষার হুক inোকাতে গো স্ট্যান্ডার্ড লাইব্রেরিতে এই প্যাটার্নটি ব্যবহার করেন:

https://golang.org/src/net/hook.go

https://golang.org/src/net/dial.go#L248

https://golang.org/src/net/dial_test.go#L701


8
ডাউনওয়েট আপনি চাইলে ডিআই এর সাথে যুক্ত বয়লারপ্লেট এড়াতে এটি ছোট প্যাকেজগুলির জন্য একটি গ্রহণযোগ্য প্যাটার্ন। প্যাকেজটি রফতানি না হওয়ায় ফাংশনযুক্ত ভেরিয়েবলটি কেবল "গ্লোবাল"। এটি একটি বৈধ বিকল্প, আমি খারাপ দিকটি উল্লেখ করেছি, আপনার নিজের অ্যাডভেঞ্চারটি বেছে নিন।
জেক

4
একটি বিষয় লক্ষণীয় হ'ল ফাংশনটি এইভাবে সংজ্ঞায়িত করা যায় না
বেন স্যান্ডলার

2
আমি @ জেকের সাথে একমত যে এই পদ্ধতির জায়গা রয়েছে।
m.kocikowski

11

আমি কিছুটা ভিন্ন পদ্ধতির ব্যবহার করছি যেখানে পাবলিক স্ট্রাক্ট পদ্ধতিগুলি ইন্টারফেস প্রয়োগ করে তবে তাদের যুক্তিগুলি কেবলমাত্র ব্যক্তিগত (অপরিবর্তিত) ফাংশনগুলিকে আবৃত করার মধ্যে সীমাবদ্ধ যা এই ইন্টারফেসগুলিকে পরামিতি হিসাবে গ্রহণ করে । এটি আপনাকে গ্রানুলারিটি দেয় যা আপনাকে কার্যত কোনও নির্ভরতার উপহাস করতে হবে এবং আপনার পরীক্ষার স্যুটটির বাইরে থেকে কোনও পরিষ্কার 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()
}

এই পদ্ধতির সম্পর্কে আমি যা পছন্দ করি তা হ'ল অপ্রত্যাশিত পদ্ধতিগুলি দেখে আপনি পরিষ্কারভাবে নির্ভর করতে পারেন তা দেখতে পাচ্ছেন। একই সাথে আপনি যে এপিআই রফতানি করেছেন তা অনেকটাই ক্লিনার এবং কম প্যারামিটারগুলি দিয়ে যেতে হবে কারণ এখানে সত্যিকারের নির্ভরতা কেবল পিতামহীন রিসিভার যা এই সমস্ত ইন্টারফেস নিজেই প্রয়োগ করে। তবুও প্রতিটি ফাংশন সম্ভাব্যভাবে এর কেবলমাত্র একটি অংশের উপর নির্ভর করে (এক, সম্ভবত দুটি ইন্টারফেস) যা রিফ্যাক্টরকে অনেক সহজ করে তোলে। আপনার কোডটি কীভাবে কেবল কার্যকারিতা স্বাক্ষরগুলি দেখে সত্যই মিলিত হয়েছে তা দেখে ভাল লাগছে, আমি মনে করি এটি গন্ধযুক্ত কোডের বিরুদ্ধে একটি শক্তিশালী সরঞ্জাম তৈরি করে।

জিনিসগুলিকে সহজ করার জন্য আমি এখানে খেলার মাঠে কোড চালানোর অনুমতি দেওয়ার জন্য সবকিছুকে একটি ফাইলে রেখেছি তবে আমি আপনাকে গিটহাবের পুরো উদাহরণটিও পরীক্ষা করে দেখার পরামর্শ দিচ্ছি, এখানে স্লাক.গো ফাইল এবং এখানে স্ল্যাক_স্টেস্ট.গো রয়েছে

এবং এখানে পুরো জিনিস :)


এটি প্রকৃতপক্ষে একটি আকর্ষণীয় পদ্ধতির এবং পরীক্ষার ফাইলে ব্যক্তিগত পদ্ধতিতে অ্যাক্সেস পাওয়ার সংস্থানটি সত্যিই দরকারী। এটি আমাকে সি ++ এর পিম্পল কৌশলটি মনে করিয়ে দেয়। তবে, আমি মনে করি এটি বলা উচিত যে ব্যক্তিগত ফাংশনগুলি পরীক্ষা করা বিপজ্জনক। ব্যক্তিগত সদস্যরা সাধারণত বাস্তবায়নের বিবরণ হিসাবে বিবেচিত হয় এবং পাবলিক ইন্টারফেসের চেয়ে সময়ের সাথে পরিবর্তিত হওয়ার সম্ভাবনা বেশি থাকে। যতক্ষণ না আপনি কেবল সর্বজনীন ইন্টারফেসের চারপাশে ব্যক্তিগত র্যাপারগুলি পরীক্ষা করেন তবে আপনার ভাল হওয়া উচিত।
c1moore

হ্যাঁ সাধারণত বলতে গেলে আমি আপনার সাথে একমত হই। এই ক্ষেত্রে যদিও ব্যক্তিগত পদ্ধতিগুলির সংস্থাগুলি জনসাধারণের মতো হ'ল তাই আপনি ঠিক একই জিনিসটি পরীক্ষা করবেন। উভয়ের মধ্যে পার্থক্যটি হ'ল ফাংশন আর্গুমেন্ট। এটি সেই কৌশলটি যা আপনাকে কোনও নির্ভরতা (বিদ্রূপ করা বা না) প্রয়োজন অনুসারে ইনজেক্ট করতে দেয়।
ফ্রান্সেসকো ক্যাসুলা

হাঁ আমি একমত. আমি কেবল বলছিলাম যতক্ষণ আপনি এগুলি সর্বজনীন পদ্ধতিতে সীমাবদ্ধ করেন যা এই সর্বজনীন লোকগুলিকে আবৃত করে রাখে, আপনার ভাল হওয়া উচিত। প্রয়োগের বিশদটি কেবল ব্যক্তিগত পদ্ধতিতে পরীক্ষা করা শুরু করবেন না।
c1moore

7

আমি এমন কিছু করতাম,

প্রধান

var getPage = get_page
func get_page (...

func downloader() {
    dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
    content := getPage(BASE_URL)
    links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
    matches := links_regexp.FindAllStringSubmatch(content, -1)
    for _, match := range matches{
        go serie_dl(match[1], match[2])
    }
}

পরীক্ষা

func TestDownloader (t *testing.T) {
    origGetPage := getPage
    getPage = mock_get_page
    defer func() {getPage = origGatePage}()
    // The rest to be written
}

// define mock_get_page and rest of the codes
func mock_get_page (....

এবং আমি _গোলং এড়ানো হবে । উটকেস ব্যবহার করা ভাল


1
আপনার পক্ষে এটি করতে পারে এমন কোনও প্যাকেজ বিকাশ করা কি সম্ভব হবে? আমি ভালো কিছু চিন্তা করছি: p := patch(mockGetPage, getPage); defer p.done()। আমি যেতে নতুন, এবং unsafeগ্রন্থাগারটি ব্যবহার করে এটি করার চেষ্টা করছিলাম , তবে সাধারণ ক্ষেত্রে এটি করা অসম্ভব বলে মনে হচ্ছে।
ভিটিলাল

@ ফ্যালেন এটি হ'ল আমার উত্তরটি প্রায় আমার এক বছর পরে লেখা হয়েছিল।
জেক

1
1. একমাত্র মিলটি হ'ল বিশ্বব্যাপী way @ জেক ২. সাধারণের চেয়ে জটিল জটিল। weberc2
পতিত

1
@ ফ্যালেন আমি আপনার উদাহরণটিকে সহজ বলে বিবেচনা করি না। যুক্তিগুলি পাস করা বৈশ্বিক রাষ্ট্রের পরিবর্তনের চেয়ে জটিল নয়, তবে বৈশ্বিক রাষ্ট্রের উপর নির্ভর করা এমন অনেক সমস্যার পরিচয় দেয় যা অন্যথায় বিদ্যমান নয়। উদাহরণস্বরূপ, আপনি যদি নিজের পরীক্ষাগুলিকে সমান্তরাল করতে চান তবে আপনাকে রেসের শর্তগুলির সাথে মোকাবিলা করতে হবে।
weberc2

এটি প্রায় একই, কিন্তু এটি :) নয়। এই উত্তরে আমি দেখতে পাচ্ছি যে কীভাবে কোনও ভারে কোনও ফাংশন নির্ধারণ করা যায় এবং কীভাবে এটি আমাকে পরীক্ষার জন্য একটি পৃথক বাস্তবায়ন বরাদ্দ করতে দেয়। আমি যে ফাংশনটি পরীক্ষা করছি তাতে আমি যুক্তিগুলি পরিবর্তন করতে পারি না, সুতরাং এটি আমার জন্য একটি দুর্দান্ত সমাধান। বিকল্পটি হ'ল মক স্ট্রাক্ট সহ রিসিভার ব্যবহার করা, কোনটি সহজ তা আমি এখনও জানি না।
অ্যালেক্সট

0

সতর্কতা: এটি এক্সিকিউটেবল ফাইলের আকারটি কিছুটা বাড়িয়ে তুলতে পারে এবং এটির জন্য একটু রানটাইম কর্মক্ষমতা ব্যয় করতে পারে। আইএমও, গোলংয়ের ম্যাক্রো বা ফাংশন ডেকরেটারের মতো বৈশিষ্ট্য থাকলে এটি আরও ভাল।

যদি আপনি এর এপিআই পরিবর্তন না করে ফাংশনগুলি উপহাস করতে চান, তবে সবচেয়ে সহজ উপায় হ'ল বাস্তবায়নটি কিছুটা পরিবর্তন করা:

func getPage(url string) string {
  if GetPageMock != nil {
    return GetPageMock()
  }

  // getPage real implementation goes here!
}

func downloader() {
  if GetPageMock != nil {
    return GetPageMock()
  }

  // getPage real implementation goes here!
}

var GetPageMock func(url string) string = nil
var DownloaderMock func() = nil

এইভাবে আমরা অন্যের মধ্যে একটি ফাংশনটিকে আসলে উপহাস করতে পারি। আরও সুবিধাজনক জন্য আমরা এই ধরণের মশকরা বয়লারপ্লেট সরবরাহ করতে পারি:

// download.go
func getPage(url string) string {
  if m.GetPageMock != nil {
    return m.GetPageMock()
  }

  // getPage real implementation goes here!
}

func downloader() {
  if m.GetPageMock != nil {
    return m.GetPageMock()
  }

  // getPage real implementation goes here!
}

type MockHandler struct {
  GetPage func(url string) string
  Downloader func()
}

var m *MockHandler = new(MockHandler)

func Mock(handler *MockHandler) {
  m = handler
}

পরীক্ষার ফাইলে:

// download_test.go
func GetPageMock(url string) string {
  // ...
}

func TestDownloader(t *testing.T) {
  Mock(&MockHandler{
    GetPage: GetPageMock,
  })

  // Test implementation goes here!

  Mock(new(MockHandler)) // Reset mocked functions
}

-2

ইউনিট পরীক্ষা বিবেচনা করা এই প্রশ্নের ডোমেন, আপনাকে https://github.com/bouk/monkey ব্যবহার করার পরামর্শ দেয় । এই প্যাকেজটি আপনাকে আপনার আসল উত্স কোডটি পরিবর্তন না করে পরীক্ষাকে মক করে তুলবে। অন্যান্য উত্তরের সাথে তুলনা করুন, এটি আরও "অ-অনুপ্রবেশ"。

প্রধান

type AA struct {
 //...
}
func (a *AA) OriginalFunc() {
//...
}

মৌখিক পরীক্ষা

var a *AA

func NewFunc(a *AA) {
 //...
}

monkey.PatchMethod(reflect.TypeOf(a), "OriginalFunc", NewFunc)

খারাপ দিকটি হ'ল:

- ডেভ.সি দ্বারা স্মরণ করিয়ে দেওয়া, এই পদ্ধতিটি অনিরাপদ। সুতরাং এটি ইউনিট পরীক্ষার বাইরে ব্যবহার করবেন না।

- নন-ইডিয়োম্যাটিক গো।

ভাল দিকটি হ'ল:

++ হস্তক্ষেপহীন। মূল কোডটি পরিবর্তন না করে আপনাকে কাজগুলি করতে বাধ্য করুন। থমাসের মতো ড।

++ আপনাকে ন্যূনতম কোড সহ প্যাকেজের আচরণ পরিবর্তন করতে পারে (সম্ভবত তৃতীয় পক্ষ দ্বারা সরবরাহ করা হয়েছে)।


1
দয়া করে এটি করবেন না। এটি সম্পূর্ণরূপে অনিরাপদ এবং বিভিন্ন গো অভ্যন্তরীণ ভাঙ্গতে পারে। এটি এমনকি দূরবর্তীভাবে idiomatic গো নাও উল্লেখ করার দরকার নেই।
ডেভ সি

1
@ ডেভসি আমি গোলং সম্পর্কে আপনার অভিজ্ঞতাকে সম্মান করি তবে আপনার মতামত নিয়ে সন্দেহ করি। 1. সুরক্ষা বলতে সফ্টওয়্যার বিকাশের জন্য সমস্ত কিছুই বোঝায় না, বৈশিষ্ট্য সমৃদ্ধ এবং সুবিধার্থে ব্যয় করে। ২. আইডোমেটিক গোলং গোলং নয়, এটির একটি অংশ। যদি একটি প্রকল্প ওপেন সোর্স হয়, তবে অন্যান্য লোকেরা এতে নোংরা খেলা সাধারণ। সম্প্রদায়ের উচিত এটি উত্সাহিত করা উচিত কমপক্ষে এটি দমন করবেন না।
ফ্রাঙ্ক ওয়াং

2
ভাষাকে গো বলা হয়। অনিরাপদ দ্বারা আমার অর্থ এটি গো রানটাইম, আবর্জনা সংগ্রহের মতো জিনিসগুলি ভেঙে ফেলতে পারে।
ডেভ সি

1
আমার কাছে, ইউনিট পরীক্ষার জন্য অনিরাপদ দুর্দান্ত। প্রতিবার ইউনিট পরীক্ষা করার সময় যদি আরও 'ইন্টারফেস' সহ রিফ্যাক্টরিং কোডের প্রয়োজন হয়। এটি আমার আরও ফিট করে যা এটি সমাধানের জন্য একটি অনিরাপদ উপায় ব্যবহার করে।
ফ্রাঙ্ক ওয়াং

1
@ ডেভিসি আমি সম্পূর্ণরূপে সম্মতি জানাই এটি একটি ভয়াবহ ধারণা (আমার উত্তরটি সর্বোচ্চ ভোট পেয়েছে এবং গৃহীত উত্তর হ'ল) ​​তবে প্যাডেন্টিক হওয়ার জন্য আমি মনে করি না যে এটি জিসিটিকে ভেঙে দেবে কারণ গো জিসি রক্ষণশীল এবং এরূপ কেসগুলি পরিচালনা করার উদ্দেশ্যে। তবে আমি সংশোধন করে খুশি হব।
weberc2
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.