Tests in Go Subdirectories: Solving the Problem Tutorials Don't Mention
\n\nHave you ever written tests in Go and found that they work perfectly in the project root, but as soon as you move them to a subdirectory — everything breaks? Sound familiar? If so — you're not alone. The question "Golang tests in sub-directory" on Stack Overflow has gathered thousands of views. And it's no surprise: Go's documentation is dry on this topic, and beginner developers often get lost.
\n\nIn this article, we'll figure out how to properly organize Go testing using nested packages, why it's needed, and how to avoid common pitfalls. Let's go!
\n\nWhy Are Tests in Subdirectories a Pain?
\n\nImagine: you have a project with the following structure:
\n\nmyapp/\n├── main.go\n├── go.mod\n└── utils/\n ├── math.go\n └── math_test.go\n\nYou run Go test from the root — and everything works. But when you try to run the tests from the utils folder, Go complains: "package myapp/utils is not in GOROOT". Sound familiar?
The problem is that Go works with packages, not folders. When you create a subdirectory, you are essentially creating a new package. And tests in it need to be run considering the project's module structure. But let's take it step by step.
\n\nBasics: How Go Sees Tests
\n\nIn Go, tests are regular files with the _test.go suffix. They can be located:
- \n
- In the same package (white-box tests) — have access to unexported functions. \n
- In a separate package with the
_testsuffix (black-box tests) — test the package as an external user. \n
When you place tests in a subdirectory, you create a new package. For example, the utils folder is the utils package. And the tests in it must belong to that package.
Example of a Correct Structure
\n\nmyapp/\n├── go.mod\n├── main.go\n└── utils/\n ├── math.go // package utils\n └── math_test.go // package utils\n\nIn the file math.go:
package utils\n\nfunc Add(a, b int) int {\n return a + b\n}\n\nIn the file math_test.go:
package utils\n\nimport "testing"\n\nfunc TestAdd(t *testing.T) {\n result := Add(2, 3)\n if result != 5 {\n t.Errorf("Expected 5, got %d", result)\n }\n}\n\nNow run the tests from the project root:
\ngo test ./utils/\n\nOr from the utils folder:
cd utils\ngo test\n\nEverything works! But what if you have a more complex structure?
\n\nNested Subdirectories: Deeper Than It Seems
\n\nLet's say you have a project with this structure:
\n\nmyapp/\n├── go.mod\n├── main.go\n└── services/\n ├── user/\n │ ├── user.go\n │ └── user_test.go\n └── order/\n ├── order.go\n └── order_test.go\n\nHere, each subdirectory is a separate package. To run all tests recursively, use three dots:
\n\ngo test ./...\n\nThis command will find all packages in the project and run their tests. Very convenient for CI/CD!
\n\nWhat If Tests Are in the Same Folder as the Code?
\n\nSometimes developers put tests in the same folder as the main code. This is fine for small projects. But for large projects, it's better to place tests in separate subdirectories — it keeps the structure cleaner.
\n\nCommon Mistakes and Their Solutions
\n\nLet's break down the most frequent problems beginners face when working with Golang tests in sub-directory.
\n\nError 1: "package is not in GOROOT"
\nCause: You are trying to run a test from a subdirectory without specifying the module. Go doesn't know which module the package belongs to.
\nSolution: Make sure you have a go.mod file in the root