2016-03-23 61 views
1

我想寫很好我已經創建的REST API的單元測試。我有這樣的簡單結構:GO單元測試結構化REST API項目

ROOT/ 
    config/ 
    handlers/ 
    lib/ 
    models/ 
    router/ 
    main.go 

config包含JSON配置和一個簡單的config.go讀取和解析JSON文件,填補了Config結構。 handlers包含控制器(即,在router/routes.go中描述的相應METHOD + URL的處理程序)。 lib包含一些數據庫,請求響應器和記錄器邏輯。 models包含要從JSON和DB映射的結構和它們的funcs。最後router包含路由器和路由定義。

現在我在GO中搜索和閱讀了很多關於單元測試REST API的文章,並且發現了或多或少令人滿意的關於如何設置測試服務器,定義路由和測試請求的文章。一切都好。 但只有當你想測試一個文件!

我現在的問題是如何爲所有處理程序設置測試環境(服務器,路線,數據庫連接)?發現here(我發現很容易理解和實現)的方法我有一個問題:或者我必須爲每個處理程序分別運行測試我必須在一個測試文件中爲所有處理程序編寫測試套件 。我相信你明白,這兩種情況都不是很高興(第一,因爲我需要保持運行go test運行所有測試成功和第二,因爲有一個測試文件覆蓋所有處理函數將變得無法維護)。

現在我成功了(根據the linked article),只是我把所有的測試和初始化代碼放入一個func文件中,但我不喜歡這種方法。

我想達成什麼是那種setUp()init()與第一觸發測試運行一次完成所有必需的變量全局可見,初始化,所有接下來的測試可能已經再次同時確保使用它們,而不需要實例化他們的這個設置文件僅編譯測試...

我不確定這是否完全清楚,或者如果這種問題需要一些代碼示例(除了什麼是already linked in the article,但我會添加任何你認爲是必需的,只是告訴我!

+0

爲什麼不可能在init函數中爲您的測試執行所有設置? – Machiel

+0

@Machiel如果我有一個init函數來設置一切,我需要爲一個測試文件定義全局變量。這意味着我無法在另一個測試文件中定義相同的變量。我想確保我能夠單獨運行每個測試並同時運行它們...... – shadyyx

+0

「測試文件」是什麼意思?我知道你有a_test.go b_test.go,但這不應該是個問題吧?如果你運行一個測試,它將所有東西都設置爲一次測試,否則它會將所有設置設置爲多次測試? – Machiel

回答

1

測試軟件包,而不是文件!

由於您正在測試處理程序/端點,因此將所有_test文件放入處理程序或路由器程序包中將是有意義的。 (例如,每個端點/處理程序一個文件)。

此外,請勿使用init()來設置您的測試。所述testing包指定一個函數具有以下特徵:

func TestMain(m *testing.M) 

生成的測試將調用TestMain(米),而不是直接運行測試 。 TestMain在主要的goroutine中運行,並且可以執行任何 設置和拆卸在m.Run的調用周圍。它應該然後 呼叫os.Exit與m.Run

裏面的TestMain功能,你可以做任何設置,您才能運行測試需要的結果。如果你有全局變量,這是申報和初始化它們的地方。每個軟件包只需要執行一次,因此將TestMain代碼放在單獨的_test文件中是有意義的。例如:

package router 

import (
    "testing" 
    "net/http/httptest" 
) 

var (
    testServer *httptest.Server 
) 

func TestMain(m *testing.M) { 
    // setup the test server 
    router := ConfigureRouter() 
    testServer = httptest.NewServer(router) 

    // run tests 
    os.Exit(m.Run()) 
} 

最後用go test my/package/router運行測試。

+0

好吧,所以初始化這個'TestMain'和全局變量我只是依靠他們在我的處理程序測試(ofc。我有一個測試每個處理程序/端點),它會工作嗎?這個'os.Exit()'會在所有軟件包的所有測試完成後調用?我需要能夠使用'go test。/ ...'運行測試,因爲這將從構建和部署腳本調用。 – shadyyx

+0

我想用銀杏做到這一點,但不幸的是,我遇到了一些問題,以及... ... http://stackoverflow.com/questions/36202934/running-ginkgo-test-suite-beforesuite-setup-before-any -spec-is-ran – shadyyx

+0

@shadyyx是的,你可以依靠他們在處理程序。但請記住,全局變量是軟件包的作用域。如果你用'go test。/ ...'測試多個軟件包,你將需要每個軟件包包含一個'TestMain'。是的,當所有測試完成時,os.Exit()將被調用。 – fl0cke

1

也許你可以把你想要的設置代碼從多個單元測試文件使用單獨測試包,只有單元測試使用?

或者你可以把設置代碼放到普通包中,並在單元測試中使用它。

之前已經有人問過,Go作者選擇不隱式提供一個測試標籤,該標籤可以用來在普通包文件中選擇性地啓用函數編譯。

+0

我試圖將* init *的東西拉到額外的包中,但這帶來了一個缺點 - 爲了使包/文件可訪問,它必須在包中沒有'_test'名稱,這使得它在內部構建生產代碼(即最終可執行文件)。這不是真的想要的......當我將init代碼拉入一個'_test'包中時,它的'init()'func中設置的變量不能被測試文件訪問。 'SetUpTests()'func我也試過... ... – shadyyx

+0

對不起。至少當我構建包時,我可以控制它們是否以我的生產代碼結束。如果我的生產代碼不導入包,則不包括該包。通過包,我的意思是一個去包,所以它的文件是在他們自己的目錄中。它們不能與生產代碼文件位於同一個目錄中。 – WeakPointer