Home  >  Article  >  Backend Development  >  Create a deadlineExceededError for unit tests with timeout: true

Create a deadlineExceededError for unit tests with timeout: true

WBOY
WBOYforward
2024-02-09 13:00:18667browse

Create a deadlineExceededError for unit tests with timeout: true

php editor Xiaoxin is here to introduce you to a tip about unit testing: create a deadlineExceededError: true for unit testing with timeout. When performing unit testing, sometimes you may encounter a test execution timeout. In this case, we can solve this problem by setting deadlineExceededError to true. This technique can help us better control and manage the execution time of the test and ensure the accuracy and reliability of the test. Next, we will introduce in detail how to use this technique to improve the efficiency and reliability of unit testing.

Question content

I'm trying to create a unit test in my project where I simulate an http client and set the response that the client must return. I need this behavior because my code needs to behave accordingly in case the http client fails with a timeout: so I need to mock the http client to return a deadlineExceededError and unit test from it.

What I've tried so far is to simulate the client do function in a way that client.do returns:

getdofunc = func(*http.request) (*http.response, error) {
    return nil, &url.error{
        op:  "post",
        err: context.deadlineexceeded,
    }
}

It works, but not completely, which means when I execute the code with this simulated behavior, the error type returned is:

error(*net/url.error) *{op: "post", url: "", err: error(context.deadlineexceedederror) {}}

This is correct again, but not completely. Why? Because if I run the code and a real timeout occurs, I get something more complete:

error(*net/url.Error) *{Op: "Post", URL: "http://localhost:4500/scan/", Err: error(*net/http.httpError) *{err: "context deadline exceeded (Client.Timeout exceeded while awaiting headers)", timeout: true}}

What interests me the most is timeout: true. If I manage to tell my mock to return it, I can assert this, which I find more complete than just asserting that the error returned is of type deadlineexceedederror.

Solution

In order to avoid overly complex testing, I recommend you adopt this approach. First, start by defining your error:

type timeouterror struct {
    err     string
    timeout bool
}

func (e *timeouterror) error() string {
    return e.err
}

func (e *timeouterror) timeout() bool {
    return e.timeout
}

In this way, timeouterror implements both the error() and timeout interfaces.
Then you have to define impersonation for the http client:

type mockclient struct{}

func (m *mockclient) do(req *http.request) (*http.response, error) {
    return nil, &timeouterror{
        err:     "context deadline exceeded (client.timeout exceeded while awaiting headers)",
        timeout: true,
    }
}

This just returns the error defined above and nil as http.response. Finally, let's look at how to write a sample unit test:

func TestSlowServer(t *testing.T) {
    r := httptest.NewRequest(http.MethodGet, "http://example.com", nil)
    client := &mockClient{}

    _, err := client.Do(r)

    fmt.Println(err.Error())
}

If you debug this test and pause with the debugger on the err variable, you will see the desired results.
This way you can achieve the functionality you want without any additional complexity. Let me know if it works for you!

The above is the detailed content of Create a deadlineExceededError for unit tests with timeout: true. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete