-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
assert: Add HTTP builder to combine request x response using builder. #1491
Conversation
Thanks for putting up this PR! 🎉 Honestly, I am not a fan of the resp, err := makeSomeHTTPCall()
require.NoError(t, err)
defer resp.Body.Close()
assert.HTTPStatus(t, resp, http.StatusOK)
assert.HTTPRespBodyContains(t, resp, "foo")
assert.HTTPRespHeaderContains(t, resp, ...) Simple assertions on a given value. But it looks like there already are some functions (like Would love to hear the thoughts of other maintainers on this. |
dfbe58e
to
8cec282
Compare
@arjunmahishi Also there would be a major change if we refactor these function to not work with handler. So when projects with already created tests would need to refactor it. Probablly this is for further discussion in some Issue and create for example Just to mention the motivation, due to not accepting this PR I need 2 testing frameworks to test the HTTP request, response. The issue I found is that it is not possible to test the response header/headers. However, to simplify the tests I thought it would be better to create 1 assert function. The developer will scope the I would like to receive at least some comment whether I have to refactor it to have just #601 here is simillar PR with header tests that could be compared with this PR. Have a nice day |
Yes. I understand the intent of this PR. Maybe I did not phrase it correctly. Don't let my comment be a blocker for this PR. The testing strategy i mentioned would require a lot of refactoring. And its probably not worth doing that. I was just putting it out there. I think the changes made in this PR are useful. Other maintainers who've been around for longer can give more contextual comments on this. |
h.Helper() | ||
} | ||
|
||
b := &builder{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the options
is optional, should the builder have some defaults?
Consider this:
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
}
func TestHttp(t *testing.T) {
assert.HTTP(t, handler, http.MethodGet, "/", nil)
}
Fails with:
=== RUN TestHttp
main_test.go:15:
Error Trace: /Users/armahishi/dev/personal/forks/testify/example/main_test.go:15
Error: Expected HTTP success status code for "/?" but received 200
Test: TestHttp
--- FAIL: TestHttp (0.00s)
FAIL
FAIL github.com/stretchr/testify/example 0.173s
FAIL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point I have added the default code for builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have made a change, based on what you said in next review step.
There are no defaults as the option would override something that is default for the builder. You mentioned that you expected that the status.code
is not tested as You did not ask for it.
As the options should be optional, I made a change when you select no option, there is nothing to be tested so the test fails. It is possible to to remove this check, however it is incorrectly tested handler
as there is not assertion
.
for _, option := range options { | ||
err := option(b) | ||
if err != nil { | ||
Fail(t, fmt.Sprintf("Failed to build http options, got error: %s", err)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only a subset of options are provided, it should only assert that.
Example:
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
}
func TestHttp(t *testing.T) {
buf := bytes.NewBufferString("hello")
assert.HTTP(t, handler, http.MethodGet, "/", nil, assert.WithExpectedBody(*buf))
}
=== RUN TestHttp
main_test.go:18:
Error Trace: /Users/armahishi/dev/personal/forks/testify/example/main_test.go:18
Error: Expected HTTP success status code for "/?" but received 200
Test: TestHttp
--- FAIL: TestHttp (0.00s)
FAIL
FAIL github.com/stretchr/testify/example 0.162s
FAIL
In general, if the all those options are not optional, they should not be variadic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To preserve the variadic options, then the code
cannot be set as default because there is option that would be set up always and therefore it is not an option, it would be a required parameter of function.
Therefore I decided to make a status.code
to be option however to make sure the usage of tests is correct, I throw a fail when no options are set as there is nothing to assert using result of handler
call.
Basically it is a prevention of missuse of test that it does nothing except the handler
execution.
assert/http_assertions.go
Outdated
if w.Code != b.code { | ||
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), w.Code)) | ||
return false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can reuse the existing assertions. It already has a lot of diff logic.
if w.Code != b.code { | |
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), w.Code)) | |
return false | |
} | |
Equal(t, b.code, w.Code) |
=== RUN TestHttp
main_test.go:15:
Error Trace: /Users/armahishi/dev/personal/forks/testify/example/main_test.go:15
Error: Expected HTTP success status code for "/?" but received 200
Test: TestHttp
--- FAIL: TestHttp (0.00s)
FAIL
FAIL github.com/stretchr/testify/example 0.161s
FAIL
VS
=== RUN TestHttp
main_test.go:15:
Error Trace: /Users/armahishi/dev/personal/forks/testify/example/main_test.go:15
Error: Not equal:
expected: 404
actual : 200
Test: TestHttp
--- FAIL: TestHttp (0.00s)
FAIL
FAIL github.com/stretchr/testify/example 0.163s
FAIL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point, however I wanted to be concise with the code style in the module, and there is not usage of Equal
even though it is possible.
As I am more sceptical to use module itself I think it is correct to not use Equal
function as if it will be changed in future, you have to rework whole http_assertions.go
module as it is dependend on that.
It is probably bad assumption but I think we can have a discussion about this and possibly make another PR with appropriate refactor of http_assertions.go
module. 😅
When no option provided there is nothing to test. Throw a Fail when no options are selected to prevent missuse of new function.
47afa36
to
09e4190
Compare
@arjunmahishi Is there any update regarding this PR? I would like to push it forward if possible. 🙂 |
This is my thinking too. I note this that proposed function also only works with http.HandlerFunc and not http.Handler, would we add another function to support http.Handler? Better to make assertions against a httptest.ResponseRecorder because this would support both standard library handlers, as well as those from other libraries that differ from stdlib such as gin and restful. |
@brackendawson Will be there any progress or just close this PR as wont do? I don't see a point what should I do differently or how to send PR with enhancement of this. |
I honestly don't see us adding more assertions that call handlers. Sorry about that. |
Summary
Adds new method into assert http_assertions.go. Should be used as generic solution for testing request parameters to response possibilities using 1 method with options.
Previous solutions did not have response header check method. However implementing that it would be necessary to create single test with 3 assert conditions.
Now it is possible to use single function to test typical HTTP response values(status, body, headers).
Changes
Add new function
HTTP(...)
that can be customized based on user needs.Use
go generate ./...
to update generated code.Add new test
TestHTTPBuilder
without example usage.Motivation
Impossible to test HTTP response headers.
assert.True(mockAssert.HTTP(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, WithCode(200), WithResponseHeader(http.Header{"Content-Type": []string{"text/plain; charset=utf-8"}}), WithExpectedBody(*bytes.NewBufferString("Hello, World!"))))
Related issues
Closes #598