is it possible to place test files in subfolder - go

When I have module and its test in the same directory it works ok.
- module1.go
- module1_test.go
But when number of files and test files grows it is hard to navigate through code.
Is it possible to place go tests to subfolder for cleaner code structure?
When I try to do it I got namespace error.
I placed file module1_test.go to folder ./test
- module1.go
- test/module1_test.go
Now I got error on testing:
test/module1_test.go:8: undefined: someFunc
My module1.go code:
package package1
func someFunc() {
}
My module1_test.go code:
package package1
import (
"testing"
)
func TestsomeFunc(t *testing.T) {
someFunc()
}

You can put the tests in another directory, but it is not common practice. Your tests will need to import the subject package and will not have access unexported methods in the subject package. This will work:
File $GOPATH/src/somepath/package1/module1.go
package package1
func SomeFunc() {
}
File $GOPATH/src/somepath/package1/test/module1_test.go
package test
import (
"testing"
"somepath/package1"
)
func TestSomeFunc(t *testing.T) {
package1.SomeFunc()
}
A couple of notes:
I changed SomeFunc to an exported method so that the test can access it.
The test imports the subject package "somepath/package1"

Related

modifying imported functions in go

I could override the builtin print() function's behavior by defining another print() in scope, as in https://play.golang.org/p/Y2ly31oXU67
Is it possible in go to alter the behavior on-the-fly of an imported function, say fmt.Println()?
If you want to 'alter' a builtin function, look at the very fine monkey patch utility https://github.com/bouk/monkey (And pay attention to the warnings, it's only really useful in test functions, and I for one reject any prod code that imports that package)
Import a different package with name "fmt" and implement whatever functions you need in that package. Here's an example:
File go.mod:
module test
File main.go
package main
import (
"test/fmt"
)
func main() {
fmt.Println("Hello, playground")
}
File fmt/fmt.go:
package fmt
import (
"fmt"
"log"
)
func Println(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
log.Printf(msg)
}
Run it on the playground.
The code in this answer does not modify the imported function as asked in the question.

Structuring local imports without GitHub in Golang

I'm building a simple app and after reading the doc on structuring go applications, I'm still confused.
I want this structure:
practice
models (packaged as models)
a
b
routers (packaged as routers)
a
b
app.go
Inside of app.go, I have the following:
package main
import (
"net/http"
// I have tried the following:
"practice/models/a"
"practice/models/b"
"practice/models"
"$GOPATH/practice/models/a"
"$GOPATH/practice/models/b"
"$GOPATH/practice/models"
...
)
func main() {
http.HandleFunc("/a", AHandler)
http.HandleFunc("/b", BHandler)
http.ListenAndServe(":8080", nil)
}
The A and B models look like this:
package models
import "net/http"
func AHandler(w http.ResponseWriter, r *http.Request) {
// code
}
Two questions:
What in the world is the right way to import these files? Do I really have to push them to github in order to be able to reference them? I understand the $GOPATH is the namespace for the entire go workspace on a local machine. My $GOPATH is set to include this directory.
Do I need to define a main method inside of these files? Can I just export a single function and have that be the handling function?
I have consulted the docs
See How to Write Go Code.
Use this directory structure:
- practice
- go.mod
- app.go
- models
- a.go
- b.go
- routers
- a.go
- b.go
where go.mod is created with the command go mod init practice where practice is the module path.
Import the packages as follows:
import (
"practice/routers"
"practice/models"
...
)
Use the imported packages like this:
func main() {
http.HandleFunc("/a", models.AHandler)
http.HandleFunc("/b", models.BHandler)
http.ListenAndServe(":8080", nil)
}
You do not need to push to github.com, even if you use github.com in the module path.
The main function in the main package is the entry point for the application. Do not define main functions in packages other than main.
What follows is the original answer based on GOPATH workspaces:
See How to Write Go Code.
Create your directory structure under $GOPATH/src.
$GOPATH
src
practice
models
routers
Import the packages as follows:
import (
"practice/routers"
"practice/models"
...
)
Use the imported packages like this:
func main() {
http.HandleFunc("/a", models.AHandler)
http.HandleFunc("/b", models.BHandler)
http.ListenAndServe(":8080", nil)
}
You do not need to push to github.com, even if you use 'github.com' in the file path.
The main function in the main package is the entry point for the application. Do not define main functions in packages other than main.
I think the other answer is out of date, you don't need to use GOPATH anymore.
Run:
go mod init yellow
Then create a file yellow.go:
package yellow
func Mix(s string) string {
return s + "Yellow"
}
Then create a file orange/orange.go:
package main
import "yellow"
func main() {
s := yellow.Mix("Red")
println(s)
}
Then build:
go build
https://golang.org/doc/code.html

My main.go file cannot see other files

I need some help understanding what is wrong with my file layout in a simple web application.
$GOPATH/src/example.com/myweb
I then have 2 files:
$GOPATH/src/example.com/myweb/main.go
$GOPATH/src/example.com/myweb/api.go
Both files have:
package main
The api.go file looks like:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type API struct {
URI string
Token string
Secret string
client *http.Client
}
...
My main.go file looks like:
package main
import (
"github.com/gorilla/mux"
"html/template"
"net/http"
)
var (
templates = template.Must(template.ParseFiles("views/home.html", "views/history.html", "views/incident.html"))
api = API{
URI: "http://localhost:3000",
Token: "abc",
Secret: "123",
}
)
func renderTemplate(w http.ResponseWriter, tmpl string, hp *HomePage) {
..
..
}
func WelcomeHandler(w http.ResponseWriter, r *http.Request) {
..
..
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", WelcomeHandler)
r.PathPrefix("/assets/").Handler(
http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
http.ListenAndServe(":9000", r)
}
In the code I excluded, I basically use structs that are defined in my api.go file, and I get this error when doing:
go run main.go
# command-line-arguments
./main.go:16: undefined: API
./main.go:23: undefined: User
What exactly am I doing wrong here?
I tried changing the package name in api.go to myweb but that didn't help.
Am I suppose to use the package name myweb? Is just 1 file suppose to have main?
You're compiling only the main.go file. You should use:
go run main.go api.go
Or:
go run *.go
If you're writing a complex application, you might add everything to packages in subdirectories and have a single main.go file. For instance, etcd has an etcdmain subdirectory/package along with other subdirectories/packages. Something like:
/alarm
/auth
/cmd
/etcdmain
...
And the main.go file is simply:
package main
import "github.com/coreos/etcd/etcdmain"
func main() {
etcdmain.Main()
}
You are using golang workspace project, which is good for the structure for your application and it also standardize.
When we use the golang workspace, you can not run single go file. You need to call go build / go install.
Install
go install example.com/myweb
The command above will compile your main package on example.com/myweb. And the myweb executable binary will be placed on the GOPATH/bin. And you can run it manually.
Build
go build example.com/myweb
The command is similar to go install but the binary executable file will be placed on the current directory when you call the command, instead of on GOPATH/bin (unless your current directory is GOPATH/bin).
For more information please check this link.

Call a function from another package in Go

I have two files main.go which is under package main, and another file with some functions in the package called functions.
My question is: How can I call a function from package main?
File 1: main.go (located in MyProj/main.go)
package main
import "fmt"
import "functions" // I dont have problem creating the reference here
func main(){
c:= functions.getValue() // <---- this is I want to do
}
File 2: functions.go (located in MyProj/functions/functions.go)
package functions
func getValue() string{
return "Hello from this another package"
}
You import the package by its import path, and reference all its exported symbols (those starting with a capital letter) through the package name, like so:
import "MyProj/functions"
functions.GetValue()
You should prefix your import in main.go with: MyProj, because, the directory the code resides in is a package name by default in Go whether you're calling it main or not. It will be named as MyProj.
package main just denotes that this file has an executable command which contains func main(). Then, you can run this code as: go run main.go. See here for more info.
You should rename your func getValue() in functions package to func GetValue(), because, only that way the func will be visible to other packages. See here for more info.
File 1: main.go (located in MyProj/main.go)
package main
import (
"fmt"
"MyProj/functions"
)
func main(){
fmt.Println(functions.GetValue())
}
File 2: functions.go (located in MyProj/functions/functions.go)
package functions
// `getValue` should be `GetValue` to be exposed to other packages.
// It should start with a capital letter.
func GetValue() string{
return "Hello from this another package"
}
Export function getValue by making 1st character of function name capital, GetValue
you can write
import(
functions "./functions"
)
func main(){
c:= functions.getValue() <-
}
If you write in gopath write this import functions "MyProj/functions" or if you are working with Docker
In Go packages, all identifiers will be exported to other packages if the first letter of the identifier name starts with an uppercase letter.
=> change getValue() to GetValue()
you need to create a go.mod file in the root directory of your project: go mod init module_name
the name of exposed function should start with capital letter
import(
"module_name/functions"
)
func main(){
functions.SomeFunction()
}

Error in importing custom packages in Go Lang

I have created a library by the name libfastget which is in the src with my program as
src
|-libfastget
| |-libfastget.go
|
|-MainProgram
|-main.go
and the libfastget exports a funtion fastget as follows
package libfastget
import (
"fmt"
"io"
)
func fastget(urlPtr *string, nPtr *int, outFilePtr *string) download {
.....
return dl
}
When I use the library in my main program
package main
import (
"fmt"
"net/http"
"os"
"libfastget"
"path/filepath"
"strings"
"flag"
"time"
)
func uploadFunc(w http.ResponseWriter, r *http.Request) {
n:=libfastget.fastget(url,4,filename)
}
}
I get the following error upon trying to build with go build
# FServe
./main.go:94: cannot refer to unexported name libfastget.fastget
./main.go:94: undefined: libfastget.fastget
The strange thing is that the library file libfastget.a is present in the pkg folder.
you would need to make your function exportable with an uppercase for its name:
func Fastget(...
Used as:
n:=libfastget.Fastget(url,4,filename)
The spec mentions: "Exported identifiers":
An identifier may be exported to permit access to it from another package. An identifier is exported if both:
the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
to export a function into another package the function identifier must start with a capital letter.
I recently started learning GO Lang (2 days back)
And what I found was you need to setup a workspace folder to make the local packages import into other projects or main.go files. I'm using VS Code editor. Please correct me if Im wrong, but this setup works fine for me.
Inside your bash_profile OR .zshrc file add below lines, update the GOPATH as per your folder path.
export GOPATH=~/projects/GO_PROJECTS
export PATH=$PATH:$GOPATH/bin:$PATH
and this is my sayHello.go file, please note to be able to export a function the func name should start with a CapitalCase SayHello
package utils
import "fmt"
func SayHello() {
fmt.Println("Hello, Ajinkya")
}
and now I am able to import utils package into main.go file
package main
import (
"go_proj1/utils"
)
func main() {
utils.SayHello()
}
set the current directory as GOPATH
or you can use local import as follows
move your main.go to the ../ directory to the libfastget.go.
i mean the files looks like:
src
|-libfastget
| |-libfastget.go
|
|-main.go
import "./libfastget"

Resources