Skip to content

[discussion]: Introducing a test helper for testing commands #736

@NucleoFusion

Description

@NucleoFusion

Topic

As we move towards expanding the test coverage of harbor-cli we will eventually need to test the commands themselves.
While we are thinking of doing integration tests with a mock harbor, I beleive we can reduce the scope of integration tests (which are more complex than simple unit tests) by including unit tests for malformed args and other cases.

We should have a test helper built for testing commands specifically since the traditional way is much more verbose and repetitive than required.

Context

Cobra ships with certain niceties for testing such as:-

    cmd := NewMyCommand() // your constructor
    cmd.SetOut(buf)
    cmd.SetErr(errBuf)
    cmd.SetArgs([]string{"--flag", "value"})

    err := cmd.Execute()

But this has repetition hence I wanted to add something like:

func Test command(t testing.Testing, cmdFunc func() *cobra.Command, ...flags) error

With this to test a command would be simplified, coupled with the tabular testing approach, testing would be just one line.

We can also make this more resilient if we can add functionality to differentiate between if the error is from the API call or the rest of the command logic.
If so we would also be able to check whether all flags and tests pass, instead of only inducing errors

Additional Information

An example testing structure with this function would look like,

// Courtesy of AI

func TestGetProjectCmd(t *testing.T) {
    tests := []struct {
        name    string
        args    []string
        wantErr string
    }{
        {
            name:    "missing required flag",
            args:    []string{},
            wantErr: "required flag \"name\" not set",
        },
        {
            name:    "empty name",
            args:    []string{"--name", ""},
            wantErr: "project name cannot be empty",
        },
        {
            name:    "valid flags reach API",
            args:    []string{"--name", "myproject"},
            wantErr: "",
        },
        {
            name:    "invalid characters in name",
            args:    []string{"--name", "my/project"},
            wantErr: "project name contains invalid characters",
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            err := testutil.RunCmdValidation(t, NewGetProjectCmd, tt.args...)

            if tt.wantErr == "" {
                assert.NoError(t, err)
            } else {
                assert.EqualError(t, err, tt.wantErr)
            }
        })
    }
}

@bupd @qcserestipy @Vad1mo What are your thoughts?
We could also then create an umbrella issue for command testing so that we can add testing to commands one by one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions