I'm interested in reassigning factory functions for testing reasons within Go, to mitigate the risk of using a factory function within a given package when wanting to mock one of its types.
I've seen people pass factory functions as arguments to a containing function, and creating a struct that holds factories as data members. Is it instead possible to keep a top-level function variable and someway overwrite one implementation with another within a given file? I've tried the below:
type AirportFactory func (string, int, int) Airport
var makeAirport AirportFactory = func(n string, x int, y int) Airport {
return airport{name: n, pos: Position{X: x, Y: y}}
}
makeAirport = func(n string, x int, y int) Airport {
return airport{name:"default", pos:Position{X:0, Y:0}}
}
But when I build the code, 6g gives me the following error on the closing line of the last assignment: non-declaration statement outside function body
This makes it seem like var
s of function types are const, at least at the top level. Is there any way to get around this?
They are not constant. You just can not assign to an already declared variable outside of a function. Something such as this will work:
func changeAirport() {
makeAirport = func(n string, x int, y int) Airport {
return airport{name:"default", pos:Position{X:0, Y:0}}
}
}
As far as go is concerned, the variable assignments outside of a function do not happen in any particular order. As a consequence, you can only do it once.
You could use the package init function to set the mock value of package variables. For example,
package main
import "fmt"
var x = 1
// set mock values of variables
func mock() {
x = 2
}
func init() {
mock()
}
func main() {
fmt.Println(x)
}
Output:
2
For your example,
package main
import "fmt"
type Position struct {
X int
Y int
}
type Airport struct {
name string
pos Position
}
type AirportFactory func(string, int, int) Airport
var makeAirport AirportFactory = func(n string, x int, y int) Airport {
return Airport{name: n, pos: Position{X: x, Y: y}}
}
// set mock values of variables
func mock() {
makeAirport = func(n string, x int, y int) Airport {
return Airport{name: "default", pos: Position{X: 0, Y: 0}}
}
}
func init() {
mock()
}
func main() {
fmt.Println(makeAirport("name", 1, 1))
}
Output:
{default {0 0}}