Practical Go. Amit Saha

Читать онлайн книгу.

Practical Go - Amit Saha


Скачать книгу
with a slice of strings containing the arguments that the program may call and verify the expected behavior. Let's look at the test configurations:

      // chap2/sub-cmd-arch/handle_command_test.go package main import ( "bytes" "testing" ) func TestHandleCommand(t *testing.T) { usageMessage := `Usage: mync [http|grpc] -h http: A HTTP client. http: <options> server Options: -verb string HTTP method (default "GET") grpc: A gRPC client. grpc: <options> server Options: -body string Body of request -method string Method to call ` // TODO Insert testConfigs from above byteBuf := new(bytes.Buffer) for _, tc := range testConfigs { err := handleCommand(byteBuf, tc.args) if tc.err == nil && err != nil { t.Fatalf("Expected nil error, got %v", err) } if tc.err != nil && err.Error() != tc.err.Error() { t.Fatalf("Expected error %v, got %v", tc.err, err) } if len(tc.output) != 0 { gotOutput := byteBuf.String() if tc.output != gotOutput { t.Errorf("Expected output to be: %#v, Got: %#v", tc.output, gotOutput) } } byteBuf.Reset() } }

      Save Listing 2.6 as handle_command_test.go in the same directory as the main package (see Listing 2.2).

       EXERCISE 2.1: TESTING SUB-COMMAND INVOCATION Update the test for the handleCommand() function to verify that the correct sub-command implementation is invoked when a valid sub-command is specified. You will find the approach suggested for the solution to Exercise 1.1 useful here as well.

      Testing the Cmd Package

      To test the cmd package, you will define similar test cases. Here are the test cases for the TestHandleHttp() function:

      You can find the complete test in chap2/sub-cmd-arch/cmd/handle_http_test.go .

      The test configurations for the TestHandleGrpc() function are as follows:

      testConfigs := []struct { args []string err error output string }{ // Test behavior when the grpc sub-command is called with no // positional argument specified { args: []string{}, err: ErrNoServerSpecified, }, // Test behavior when the grpc sub-command is called with "-h" { args: []string{"-h"}, err: errors.New("flag: help requested"), output: usageMessage, }, // Test behavior when the http sub-command is called // with a positional argument specifying the server URL { args: []string{"-method", "service.host.local/method", "-body", "{}", "http://localhost"}, err: nil, output: "Executing grpc command\n", }, }

      You can find the complete test in chap2/sub-cmd-arch/cmd/handle_grpc_test.go .

      The source tree for the application should now look like the following:

      From the root of the module, run all of the tests:

      $ go test -v ./… === RUN TestHandleCommand --- PASS: TestHandleCommand (0.00s) PASS ok github.com/practicalgo/code/chap2/sub-cmd-arch 0.456s === RUN TestHandleGrpc --- PASS: TestHandleGrpc (0.00s) === RUN TestHandleHttp --- PASS: TestHandleHttp (0.00s) PASS ok github.com/practicalgo/code/chap2/sub-cmd-arch/cmd 0.720s

      Great. You now have unit tests for both the packages. You have written a test to verify that the main package displays an error when an empty or invalid sub-command is specified and calls the right sub-command when a valid sub-command is specified. You have also written a test for the cmd package to verify that the sub-command implementations behave as expected.

      In Exercise 2.2, you will add a validation to the http sub-command to allow only three HTTP methods: GET, POST, and HEAD .

       EXERCISE 2.2: HTTP METHOD VALIDATOR You will add validation to the http sub-command in this exercise. You will ensure that the method option only allows three values: GET (the default), POST , and HEAD .

       If the method yields anything other than these values, the program should exit with a non-zero exit code and print the error “Invalid HTTP method”. Write tests to verify the validation.

      In this section, you learned how to write a command-line application with sub-commands. When you are writing a large command-line application, organizing the functionality into separate sub-commands improves the user experience. Next, you will learn how to implement a degree of predictability and robustness in command-line applications.

      User Input with Deadlines

      Let's consider an example where your program asks for user input and the user has to type in the input and press the Enter key within 5 seconds else it will move on with a default name. Though a contrived example, it illustrates how you can enforce a time-out on any custom code in your application.

      Let's look at the main() function first:


Скачать книгу