Golang httptest

簡介 用go開發API通常會用到 net/http pacakge,其提供基本的 http 客戶端和服務器功,允許使用者建立 http server、處理 http 請求以及發送 http 請求到其他server。 然而之前沒有寫測試的習慣,在學TDD的時候發現一個有趣的package - net/http/httptest net/http/httptest 套件主要用於測試 http 服務器,可以模擬 http 請求和回應,讓測試者可以在沒有實際server的情況下測試 http 操作相關的函數,而不用依賴網路和實際的http server。 Key function in net/http/httptest 在進入實際操作前先說明package裡面重要的函數和屬性。 // net/http/httptest func NewServer(handler http.Handler) *Server { ts := NewUnstartedServer(handler) ts.Start() return ts } // net/http type Handler interface { ServeHTTP(ResponseWriter, *Request) } // The HandlerFunc type is an adapter to allow the use of // ordinary functions as HTTP handlers. If f is a function // with the appropriate signature, HandlerFunc(f) is a // Handler that calls f....

March 15, 2024 · 3 min

Dependency Injection Mocking with Go

在軟體開發有個有個很重要的概念叫做SOLID,這五個單字其實各自說明不同的設計方法,目的是為了讓軟體開發及維護更加容易。這邊特別要提到的是D代表的依賴反轉原則 (Dependency Inversion),主要是高層次的模組不應該依賴低層次的模組,應該提供介面讓較低層次的模組實現,降低不同模組之間的耦合程度,提高程式碼的可測試性。此篇文章會先介紹何謂依賴注入,再分別透過Learn Go with Tests書中的例子實作Dependency Injection和mocking。 依賴注入 “依賴”如果以蓋大樓來比喻,如果要蓋一樓需要依賴地基,蓋二樓則需要依賴一樓和地基已經蓋好。”注入”則是將我們蓋房子所需要的資源(材料, 工人)提供給建造的過程,建造過程就可以更加靈活且可擴展,例如一樓是水泥房,二樓想要充滿自然元素,就可以將注入的原料改為木材,也就是隨時可以根據需求替換要注入的項目。 Go裡面strcut用來定義物件,interface用來定義物件的行為,再搭配struct和interface舉一個更生活化的例子 - 買咖啡 介面(Interface):「咖啡」。它是一個通用的概念,代表了一切可以被當作咖啡的飲品。它有一些通用特性,比如含有咖啡因、熱的、無糖、放在杯子裡。 結構體(Struct):拿鐵、美式、卡布奇諾這接自己定義的struct,都可以看成是「咖啡」介面的具體實現。它們都是咖啡,但每一種都有其獨特的製作方法(method)。 到了星巴克,你不會說要哪一種咖啡,因為實做”咖啡”這個介面的有很多種飲料。這時會說「我要一杯拿鐵」,其實是將拿鐵這個struct注入到訂單,店員就會依照你的需求執行定義好的行為來實現正確的咖啡種類。 實踐方式 Constructor function injection CoffeeService 依賴 CoffeeOrder ,也就是消費者點什麼咖啡,店員才會提供相對應的咖啡服務。透過constructor function NewCoffeeService,將 CoffeeOrder 這個依賴作為參數注入,並在 CoffeeService 中使用。 所以當我們需要建立一個CoffeeService 實例時,首先需要根據消費者的選擇建立一個 CoffeeOrder 實例,並將其作為參數傳遞给 NewCoffeeService 函數。CoffeeService 不需要知道 CoffeeOrder 是如何建立的,只需要知道它可以使用 CoffeeOrder,藉此增加靈活性和可擴展性。 type CoffeeOrder struct { Type string Size string } type CoffeeService struct { order *CoffeeOrder } func NewCoffeeService (order *CoffeeOrder) *CoffeeService{ return &CoffeeService{order : order} } Setter injection Setter 注入允許在物件建立後的任何時間點注入依賴,以下面 setter 方法為例。做咖啡的服務會依賴於訂單,可以將 CoffeeOrder 這個依賴作為參數注入作為咖啡服務的屬性。...

March 3, 2024 · 3 min

Maps and memory leaks(#28)

前言 此為跟<learn go with tests>讀書會成員在分享Maps章節,有人分享的文章,原文見於100 Go Mistakes and How to Avoid Them,此篇針對作者提到的第28個常見錯誤,做一些讀後記錄。 Map in Go 此篇不會介紹在go裡面如何操作map, 而是希望更了解map設計原理,並藉由文章來探討為什麼可能發生memory leaks. 在Go的官方部落格關於map是以此做為開頭 One of the most useful data structures in computer science is the hash table. Many hash table implementations exist with varying properties, but in general they offer fast lookups, adds, and deletes. Go provides a built-in map type that implements a hash table. 在計算機科學的世界裡面,hash table是一種很常使用的資料結構。hash table會用hash function將key產出獨特的hash value,然後分配到不同的bucket。在Python裡面有dictionary, 在Go裡面則是透過Map實現hash table Map可看成由一個陣列構成,而陣列的每個元素都是指向一個bucket的pointer。每個bucket包含了一系列的key-value pairs。當要尋找或是新增Map中的元素時,會使用key的hash valuse來確定其在陣列中的位置,然後在對應的桶中進行操作。...

January 18, 2024 · 3 min

MySQL protocol 與 Wireshark實作

Client/Server protocol MySQL客戶端和MySQL伺服器端通訊的協議,分為Connection Phase & Command Phase,前者負責驗證資料的交換,後者為指令的接受和執行。 連線過程參考下圖,圖片取自Turing blog three way handshake 建立 tcp 連線 Server initiate connection phase with sending handshake packet => server greeting Client => login request Server => (auto switch request), response OK clinet initiate command phase => query Server => response ok client => prepare statment Server => response to prepare(指定一個唯一的識別碼statement id) client => excute statment (有statement id 去辨識屬於哪個prepare statement) Server => response ok client => request close statement client 發送tcp fin flag Golang 程式碼參考 package main import ( "database/sql" "fmt" "time" _ "github....

November 11, 2023 · 2 min

Golang Pointer

前言 指標大概是我一開始學習golang最不適應的概念,最一開始學程式是由JavaScript入門,到wehelp後再學習用python 的flask框架寫網頁,這兩種語言都沒有指標的概念。而Go為了實現更高效的演算法及展現其高併發的特性,所以存有指標的方法來操作內存,當然相信自己學習時間不算久,也非EE 或CS背景,對指標瞭解可能還不夠全面,只能盡力就我了解的進行說明,如果有錯還請各方大神指正。 值 & 指標 當我們將int、string、struct這類的值傳給函式的時候(圖一),Go語言會在函式中複製這些值,建立新的變數,也就代表如果是在函式對參數做修改時候,原始的值是不會有影響的,而如果要修改原本的值,就要透過所謂的 指標變數。 (圖一,圖片來源 : Udemy Go: The Complete Developer’s Guide (Golang)) 我們可以在記憶體儲存資料非常簡單看成是一個抽屜,每個變數到會找到一個抽屜來儲存資料,而每個抽屜都有一個地址對應一筆資料(圖二),所謂的值與指標變數的關係可以參考圖三,也可以幫助理解。 宣告一個int型別的變數x,其值初始化為3,這個3在記憶體裡面會有個地址0x88FFF。並可以透過在變數前面加上ampersand符號,取得該變數在記憶體的地址。 宣告一個int型別的指標變數xPtr,*int代表一個指向int的指針,為一種type description。並透過將xPtr初始化為&x,取得該變數在記憶體的地址。 最後如果有需要存取原本的值,或修改原本的值,可以透過在指標變數前面加上*符號進行反解(dereferencing)。如果(ex : fmt.Println(*xPtr)可以得到3 )。 (圖二,自行繪製) (圖三,圖片來源 : Golang 指標基礎 Pointer - 記憶體位址、指標變數與資料型態、反解指標 By 彭彭) 介紹完值和指標宣告與反解的流程,會發現用到兩次*符號,但這兩次其實是代表不同個功用,參考下圖四 (圖四,自行繪製) 同時繪製圖五再次說明*符號與&符號的當作運算符號時候的功能 (圖五,自行繪製) 實作程式碼 以下面程式碼為例,一開始會先印出x等於3,但當我們將int傳給函式的時候,會在函式複製值,建立新的變數,所以如果要修改原本的值,傳入的變數必須為指標變數,故modifyInt函式的參數為(x *int)。 而當我們定義型別為*int,傳入的參數就必須是記憶體位置,故使用&x作為參數帶入modifyInt()函式,最後透過在modifyInt()使用*x進行反解,取得原本記憶體位置的值並重新賦值為50,可以發現不管是一開始的x變數,或是執行完modifyInt()函式的x變數,其值都變成50了。 package main import "fmt" var x int=3 func modifyInt(x *int) { *x = 50 fmt.Println("Inside function :", *x) } func main() { fmt.Println("At first, x eqaul to :", x) modifyInt(&x) fmt....

October 22, 2023 · 1 min