-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add test pattern for main-method (#75)
Signed-off-by: Tronje Krop <[email protected]>
- Loading branch information
Showing
4 changed files
with
98 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.0.7 | ||
0.0.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,19 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
"os/exec" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/tkrop/go-testing/test" | ||
) | ||
|
||
type MainParams struct { | ||
args []string | ||
expectExitCode int | ||
} | ||
|
||
var testMainParams = map[string]MainParams{ | ||
"no mock to generate": { | ||
args: []string{"mock"}, | ||
expectExitCode: 0, | ||
var testMainParams = map[string]test.MainParams{ | ||
"no mocks": { | ||
Args: []string{"mock"}, | ||
Env: []string{}, | ||
ExitCode: 0, | ||
}, | ||
} | ||
|
||
func TestMain(t *testing.T) { | ||
test.Map(t, testMainParams). | ||
Run(func(t test.Test, param MainParams) { | ||
// Switch to execute main function in test process. | ||
if name := os.Getenv("TEST"); name != "" { | ||
// Ensure only expected test is running. | ||
if name == t.Name() { | ||
os.Args = param.args | ||
main() | ||
assert.Fail(t, "os-exit not called") | ||
} | ||
// Skip other test. | ||
return | ||
} | ||
|
||
// Call the main function in a separate process to prevent capture | ||
// regular process exit behavior. | ||
cmd := exec.Command(os.Args[0], "-test.run=TestMain") | ||
cmd.Env = append(os.Environ(), "TEST="+t.Name()) | ||
if err := cmd.Run(); err != nil || param.expectExitCode != 0 { | ||
errExit := &exec.ExitError{} | ||
if errors.As(err, &errExit) { | ||
assert.Equal(t, param.expectExitCode, errExit.ExitCode()) | ||
} else { | ||
assert.Fail(t, "unexpected error", err) | ||
} | ||
} | ||
}) | ||
test.Map(t, testMainParams).Run(test.TestMain(main)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package test | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
"os/exec" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
// MainParams provides the test parameters for testing a `main`-method. | ||
type MainParams struct { | ||
Args []string | ||
Env []string | ||
ExitCode int | ||
} | ||
|
||
// TestMain creates a test function that runs the given `main`-method in a | ||
// separate test process to allow capturing the exit code and checking it | ||
// against the expectation. This can be applied as follows: | ||
// | ||
// testMainParams := map[string]test.MainParams{ | ||
// "no mocks": { | ||
// Args: []string{"mock"}, | ||
// Env: []string{}, | ||
// ExitCode: 0, | ||
// }, | ||
// } | ||
// | ||
// func TestMain(t *testing.T) { | ||
// test.Map(t, testMainParams).Run(test.TestMain(main)) | ||
// } | ||
// | ||
// The test method is spawning a new test using the `TEST` environment variable | ||
// to select the expected parameter set containing the command line arguments | ||
// (`Args`) to execute in the spawned process. The test instance is also called | ||
// setting the given additional environment variables (`Env`) to allow | ||
// modification of the test environment. | ||
func TestMain(main func()) func(t Test, param MainParams) { | ||
return func(t Test, param MainParams) { | ||
// Switch to execute main function in test process. | ||
if name := os.Getenv("TEST"); name != "" { | ||
// Ensure only expected test is running. | ||
if name == t.Name() { | ||
os.Args = param.Args | ||
main() | ||
require.Fail(t, "os-exit not called") | ||
} | ||
// Skip unexpected tests. | ||
return | ||
} | ||
|
||
// Call the main function in a separate process to prevent capture | ||
// regular process exit behavior. | ||
// #nosec G204 -- secured by calling only the test instance. | ||
cmd := exec.Command(os.Args[0], "-test.run="+t.(*Tester).t.Name()) | ||
cmd.Env = append(append(os.Environ(), "TEST="+t.Name()), param.Env...) | ||
if err := cmd.Run(); err != nil || param.ExitCode != 0 { | ||
errExit := &exec.ExitError{} | ||
if errors.As(err, &errExit) { | ||
require.Equal(t, param.ExitCode, errExit.ExitCode()) | ||
} else { | ||
require.Fail(t, "unexpected error", err) | ||
} | ||
} | ||
} | ||
} |