-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Details
Create unit tests to verify CLI functionality for command handlers. If possible, add integration tests to test against CLI binary.
Motivation
The purpose of doing this is to verify CLI functionality and make sure this handles all the error/success cases we think it does. Unit tests like this can speed up development and iteration because we don't have to manually verify the CLI works like we want it to, all we have to do is run go test ./...
.
Part of this involves making the code more test-able by breaking up commands into smaller functions that we can easily verify. This also means clearly identifying and separating dependencies to allow easier mocking so when writing a test for the functions in cli/runner/run.go
we are only testing the code in that file, not also testing the code in cli/runner/client/client.go
.
Possible Implementation Steps
1. Make Requester Mocks
Make a directory such as cli/runner/client/mocks
to contain mocks for the Requester
interface. Then you can generate mocks of the Requester interface by using the mockgen CLI. See an example from the Makefile: https://github.com/camerondurham/runner/blob/2d02bbcc19294dead678d9aa7b1ed6c885018d2c/Makefile#L80
Now you can create a requester and mock its behavior when testing the CLI.
2. Refactor CLI functions so the Requester
is passed into function
This step is needed so we can make the CLI functions use the mocked requester created in 1 instead of making a "real" one.
To do this, we can refactor the CLI into the CliClient
by making a struct with the CLI's dependencies. An example of this structure is the runner server Client struct: https://github.com/camerondurham/runner/blob/2d02bbcc19294dead678d9aa7b1ed6c885018d2c/cli/runner/client/client.go#L28-L31
What this allows is the ability to inject the Runner Server Client mocks.
Since the CLI really only needs the Client
, the CliClient
can be something like this:
type CliClient struct {
client Requester
}
Then we can separate the runner CLI specific logic into refactor the the CLI logic into pointer receivers:
func (cli *CliClient) run(lang string, filename string) (*api.RunResponse, error) {
// check language and load file
...
return cli.client.Run(&RunRequest{...})
}
3. Implement the unit tests
Now you can create unit tests that will test the CliClient
structs created in 2. It will probably look something like this
cli := &CliClient{
client: mocks.NewMockRequester()
}
See this snippet for how to make specific responses for the generated mocks:
Subtasks
- unit test for
langs
command (Run function) - unit test for
run
command (Run function)
Metadata
Metadata
Assignees
Labels
Projects
Status