Hi I'm trying to make my function unit testable. One of the suggestion was to assign the function into a variable and make it globally accessible. I just did that but now I'm experiencing a Initialization loop below is my code
////////////////////////
// main.go
////////////////////////
func DownloadFile(filename string) {
// Initialized request variable here
// ... doing initialization
// End of initialization
res = ProcessDownload(request)
if res == 401 {
return doRetry(filename)
}
// some code here
return downloadFile(filename)
}
func DoRetry(filename string) {
// Doing some database insert/updating
return downloadFile(string)
}
And in my other file I assign this function into variable
//////////////////////
// global.go
//////////////////////
var downloadFile = DownloadFile
var doRetry = DoRetry
The reason I did this in the global.go was to make the DoRetry and DownloadFile unit testable. Meaning with this method I can MOCK the function without creating an interface. Since this is just a standalone function and don't need to be within a certain class. All the rest of the variable is ok but when it comes to a function doing a recursive behavior I get the error below
./global.go:22:5: initialization loop:
/go/src/project/global.go:22:5 downloadFile refers to
/go/src/project/process.go:403:99 DownloadFile refers to
/go/src/project/global.go:23:5 doRetry refers to
/go/src/project/process.go:394:89 DoRetry refers to
/go/src/project/global.go:22:5 downloadFile
FAIL project [build failed]
I know this maybe a duplicate in here but I can't see how the solution in here solve my problem.
Please help me on this. Thanks I read about mocking a function in this link
https://husobee.github.io/golang/testing/unit-test/2015/06/08/golang-unit-testing.html
The solution is to not assign values when you declare your downloadFile
and doRetry
function variables, but "defer" the initialization to a package init()
function, like this:
var downloadFile func(string) //= DownloadFile
var doRetry func(string) //= DoRetry
func init() {
downloadFile = DownloadFile
doRetry = DoRetry
}
This way the variables first will be initialized with nil
(zero value for function types) which means they don't depend on the DownloadFile()
and DoRetry()
functions, and later when the package init()
function runs, that will assign the function values to the variables, so no initialization loop will occur.