Skip to content

Commit 3a81b5e

Browse files
author
ryan nemeth
committed
Merge branch 'main' of github.com:rnemeth90/rnemeth90.github.io
2 parents e894213 + 276e6f3 commit 3a81b5e

File tree

1 file changed

+22
-35
lines changed

1 file changed

+22
-35
lines changed

content/posts/2025-11-02-go-mod-breaks-tests.md

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,34 @@ categories:
88
- Golang
99
- Programming
1010
---
11-
1211
## Introduction
1312
If you’ve ever initialized a new Go project with `go mod init main` and later tried to write tests for it, you may have seen this cryptic error:
14-
15-
###
13+
```
1614
cannot import "main"
17-
###
15+
```
1816

1917
At first glance, this doesn’t make much sense — after all, your code and tests are both in `package main`. However, there’s a subtle interaction between how Go handles modules, packages, and test harnesses that causes this issue. Let’s walk through what’s actually happening.
2018

2119
---
22-
2320
## Setting Up the Problem
2421

2522
### The `go.mod` File
2623
When you initialize a new Go module for an executable project, it’s common to do something like:
2724

28-
###
25+
```Golang
2926
go mod init main
30-
###
27+
```
3128

3229
That creates the following `go.mod` file:
3330

34-
###
31+
```Golang
3532
module main
3633
go 1.25.3
37-
###
34+
```
3835

3936
Then you might have a simple file like this:
4037

41-
###
38+
```Golang
4239
package main
4340

4441
func main() {
@@ -48,73 +45,66 @@ func main() {
4845
func square(n int) int {
4946
return n * n
5047
}
51-
###
48+
```
5249

5350
Now you decide to write a quick unit test in `main_test.go`:
5451

55-
###
52+
```Golang
5653
package main
5754

5855
import "testing"
5956

6057
func TestSquare(t *testing.T) {
6158
t.Log("Test successful")
6259
}
63-
###
60+
```
6461

6562
At this point, everything looks fine — until you run:
6663

67-
###
64+
```bash
6865
go test
69-
###
66+
```
7067

7168
and get the following output:
7269

73-
###
70+
```bash
7471
# main.test
7572
$WORK/b001/_testmain.go:14:8: could not import main (cannot import "main")
7673
FAIL main [build failed]
7774
FAIL
78-
###
75+
```
7976

8077
---
81-
8278
## Why This Happens
83-
When you run `go test`, the Go toolchain generates a temporary test harness (a `_testmain.go` file). This harness imports the package under test so that it can invoke your test functions.
84-
85-
Here’s the catch: the test harness **must import the module** under its module path. When your module path is literally `"main"`, the compiler refuses — because `main` is reserved for executables and cannot be imported like a normal package.
86-
87-
This only affects `go test` (and `go test .`), because those commands rely on the generated import. When you explicitly specify files (e.g., `go test *.go`), Go skips module resolution and compiles everything together manually, avoiding the import step entirely.
79+
When you run `go test`, the Go toolchain generates a temporary test harness (a `_testmain.go` file). This harness imports the package under test so that it can invoke your test functions. Here’s the catch: the test harness **must import the module** under its module path. When your module path is literally `"main"`, the compiler refuses — because `main` is reserved for executables and cannot be imported like a normal package. This only affects `go test` (and `go test .`), because those commands rely on the generated import. When you explicitly specify files (e.g., `go test *.go`), Go skips module resolution and compiles everything together manually, avoiding the import step entirely.
8880

8981
---
90-
9182
## The Fix
9283

9384
### Option 1: Rename the Module
9485
Change your `go.mod` file to use a different name, for example:
9586

96-
###
87+
```Golang
9788
module myapp
9889
go 1.25.3
99-
###
90+
```
10091

10192
Then rerun:
10293

103-
###
94+
```bash
10495
go test
105-
###
96+
```
10697

10798
You should now see:
10899

109-
###
100+
```bash
110101
ok myapp 0.35s
111-
###
102+
```
112103

113104
### Option 2: Move Testable Code Out of `main`
114105
In most cases, your `main` package should be minimal — it should only wire dependencies together. Any functions that need unit tests should live in a separate package (for example, `internal/mathutil`), which can then be imported both from your main application and from your test files.
115106

116107
---
117-
118108
## Key Takeaways
119109

120110
- The Go test harness always imports the package under test.
@@ -123,8 +113,5 @@ In most cases, your `main` package should be minimal — it should only wire dep
123113
- Reserve `main` strictly for integration and startup logic.
124114

125115
---
126-
127116
## Conclusion
128-
This issue isn’t a compiler bug — it’s just an edge case that surfaces when your module path collides with Go’s internal naming conventions.
129-
130-
If you ever see `cannot import "main"` when testing, remember: rename the module or refactor your code to follow Go’s standard package layout.
117+
This issue isn’t a compiler bug — it’s just an edge case that surfaces when your module path collides with Go’s internal naming conventions. If you ever see `cannot import "main"` when testing, remember: rename the module or refactor your code to follow Go’s standard package layout.

0 commit comments

Comments
 (0)