Repository: stretchr/testify
Pull request #933 (2020-04-26 11:13:46)

Optimise runtime for passing tests
## Summary
Move some calls to `testing.Helper()` to reduce overhead.

## Changes
Move call to `Helper()` after the check in various straightforward `assert` cases.

~Short-circuit `require.NoError()` and `require.NoErrorf()` so they do not call `Helper()` when no error is found.~ - deferred till another time

## Motivation
`Helper()` in the standard Go runtime fetches a stack trace from the runtime, so is slow for calls that are made many times.  However, `Helper()` only makes a difference if the call throws an error, so we can avoid that overhead in many cases which are otherwise cheap.

## Related issues
#766 (not a full fix)


boyan-soubachov: I like the idea behind this PR but there are several things that need to happen.
1) Most importantly, could you please run a benchmark (most likely with `testing.TB`) to prove that the changes _actually_ reduce the run time of tests. This is also a great way for us to gauge by what factor the speed-up happens
2) It seems you've forgotten to run the `go generate ./...` function before committing as we get an error in the builds
> Go generate had not been run

bboreham: > run the `go generate ./...` function 

This information is not in CONTRIBUTING.md.  Would you like a PR to move it from README.md and add a link?
boyan-soubachov: Yea, that makes sense. Thank you 

> On 28 Apr 2020, at 05:29, Bryan Boreham <notifications@github.com> wrote:
> 
> ﻿
> run the go generate ./... function
> 
> This information is not in CONTRIBUTING.md. Would you like a PR to move it from README.md and add a link?
> 
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub, or unsubscribe.

bboreham: I didn't realise `require.go` was generated; changing `require.NoError` will take a bit more work.

I have re-pushed without that commit and with a benchmark.

Before (best of 5):
```
BenchmarkNotNil-2   	 1250132	       919 ns/op	     216 B/op	       2 allocs/op
```
After:
```
BenchmarkNotNil-2   	80539458	        14.8 ns/op	       0 B/op	       0 allocs/op
```

> most likely with `testing.TB`

I didn't get this bit.  Could you explain more?
boyan-soubachov: > I didn't realise `require.go` was generated; changing `require.NoError` will take a bit more work.

Almost everything in `assert` and `require` is generated, it all gets derived from `assertions.go`. I don't think you should have any problems with `require.NoError()`. What kind of issues do you foresee?

> 
> I have re-pushed without that commit and with a benchmark.
> 
> Before (best of 5):
> 
> ```
> BenchmarkNotNil-2   	 1250132	       919 ns/op	     216 B/op	       2 allocs/op
> ```
> 
> After:
> 
> ```
> BenchmarkNotNil-2   	80539458	        14.8 ns/op	       0 B/op	       0 allocs/op
> ```
> 
That looks great!

> > most likely with `testing.TB`
> 
> I didn't get this bit. Could you explain more?

What I meant is that we could change the unit tests of some (or all if you're so inclined) of the functions you optimised to use `testing.TB` which allows benchmarks to be run. There's no need to assert that the new method is faster but it does help in being able to easily compare the performance difference.



Patch:
diff --git a/assert/assertion_format.go b/assert/assertion_format.go
index c07387d..582b44f 100644
--- a/assert/assertion_format.go
+++ b/assert/assertion_format.go
@@ -6,6 +6,7 @@
 package assert
 
 import (
+	io "io"
 	http "net/http"
 	url "net/url"
 	time "time"
@@ -201,11 +202,11 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg
 //  assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+	return HTTPBodyContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
 }
 
 // HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -214,11 +215,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
 //  assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+	return HTTPBodyNotContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
 }
 
 // HTTPErrorf asserts that a specified handler returns an error status code.
diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go
index d55c980..538dc2b 100644
--- a/assert/assertion_forward.go
+++ b/assert/assertion_forward.go
@@ -6,6 +6,7 @@
 package assert
 
 import (
+	io "io"
 	http "net/http"
 	url "net/url"
 	time "time"
@@ -385,11 +386,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
 //  a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+	return HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
 }
 
 // HTTPBodyContainsf asserts that a specified handler returns a
@@ -398,11 +399,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
 //  a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+	return HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
 }
 
 // HTTPBodyNotContains asserts that a specified handler returns a
@@ -411,11 +412,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
 //  a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+	return HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
 }
 
 // HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -424,11 +425,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
 //  a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+	return HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
 }
 
 // HTTPError asserts that a specified handler returns an error status code.
diff --git a/assert/assertions.go b/assert/assertions.go
index bfbe9cf..596119a 100644
--- a/assert/assertions.go
+++ b/assert/assertions.go
@@ -19,7 +19,7 @@ import (
 
 	"github.com/davecgh/go-spew/spew"
 	"github.com/pmezard/go-difflib/difflib"
-	yaml "gopkg.in/yaml.v2"
+	yaml "gopkg.in/yaml.v3"
 )
 
 //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
@@ -496,12 +496,12 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
 //
 //    assert.NotNil(t, err)
 func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
 	if !isNil(object) {
 		return true
 	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
 	return Fail(t, "Expected value not to be nil.", msgAndArgs...)
 }
 
@@ -542,12 +542,12 @@ func isNil(object interface{}) bool {
 //
 //    assert.Nil(t, err)
 func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
 	if isNil(object) {
 		return true
 	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
 	return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
 }
 
@@ -584,12 +584,11 @@ func isEmpty(object interface{}) bool {
 //
 //  assert.Empty(t, obj)
 func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
-
 	pass := isEmpty(object)
 	if !pass {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
 	}
 
@@ -604,12 +603,11 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
 //    assert.Equal(t, "two", obj[1])
 //  }
 func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
-
 	pass := !isEmpty(object)
 	if !pass {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
 	}
 
@@ -652,16 +650,10 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
 //
 //    assert.True(t, myBool)
 func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
-	if h, ok := t.(interface {
-		Helper()
-	}); ok {
-		h.Helper()
-	}
-
 	if !value {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		return Fail(t, "Should be true", msgAndArgs...)
 	}
 
@@ -673,11 +665,10 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
 //
 //    assert.False(t, myBool)
 func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
-
 	if value {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		return Fail(t, "Should be false", msgAndArgs...)
 	}
 
@@ -1110,6 +1101,8 @@ func toFloat(x interface{}) (float64, bool) {
 	xok := true
 
 	switch xn := x.(type) {
+	case uint:
+		xf = float64(xn)
 	case uint8:
 		xf = float64(xn)
 	case uint16:
@@ -1317,10 +1310,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
 //	   assert.Equal(t, expectedObj, actualObj)
 //   }
 func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
 	if err != nil {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
 	}
 
@@ -1334,11 +1327,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
 //	   assert.Equal(t, expectedError, err)
 //   }
 func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
-	if h, ok := t.(tHelper); ok {
-		h.Helper()
-	}
-
 	if err == nil {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
 		return Fail(t, "An error is expected but got nil.", msgAndArgs...)
 	}
 
diff --git a/assert/http_assertions.go b/assert/http_assertions.go
index 4ed341d..30ef7cc 100644
--- a/assert/http_assertions.go
+++ b/assert/http_assertions.go
@@ -2,6 +2,7 @@ package assert
 
 import (
 	"fmt"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -111,9 +112,13 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
 
 // HTTPBody is a helper that returns HTTP body of the response. It returns
 // empty string if building a new request fails.
-func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
+func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values, body io.Reader) string {
 	w := httptest.NewRecorder()
-	req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
+
+	if values != nil {
+		url = url + "?" + values.Encode()
+	}
+	req, err := http.NewRequest(method, url, body)
 	if err != nil {
 		return ""
 	}
@@ -127,13 +132,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
 //  assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	body := HTTPBody(handler, method, url, values)
+	httpBody := HTTPBody(handler, method, url, values, body)
 
-	contains := strings.Contains(body, fmt.Sprint(str))
+	contains := strings.Contains(httpBody, fmt.Sprint(str))
 	if !contains {
 		Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
 	}
@@ -147,13 +152,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
 //  assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	body := HTTPBody(handler, method, url, values)
+	httpBody := HTTPBody(handler, method, url, values, body)
 
-	contains := strings.Contains(body, fmt.Sprint(str))
+	contains := strings.Contains(httpBody, fmt.Sprint(str))
 	if contains {
 		Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
 	}
diff --git a/go.mod b/go.mod
index 624efdd..ed0b50b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,10 +1,10 @@
 module github.com/stretchr/testify
 
+go 1.13
+
 require (
 	github.com/davecgh/go-spew v1.1.0
 	github.com/pmezard/go-difflib v1.0.0
 	github.com/stretchr/objx v0.1.0
-	gopkg.in/yaml.v2 v2.2.2
+	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
 )
-
-go 1.13
diff --git a/go.sum b/go.sum
index 565b1c3..e23c325 100644
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,10 @@
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/mock/mock.go b/mock/mock.go
index a6d9526..c6df448 100644
--- a/mock/mock.go
+++ b/mock/mock.go
@@ -855,7 +855,7 @@ func (args Arguments) String(indexOrNil ...int) string {
 		// normal String() method - return a string representation of the args
 		var argsStr []string
 		for _, arg := range args {
-			argsStr = append(argsStr, reflect.TypeOf(arg).String())
+			argsStr = append(argsStr, fmt.Sprintf("%T", arg)) // handles nil nicely
 		}
 		return strings.Join(argsStr, ",")
 	} else if len(indexOrNil) == 1 {
diff --git a/require/require.go b/require/require.go
index 22784c1..d757754 100644
--- a/require/require.go
+++ b/require/require.go
@@ -7,6 +7,7 @@ package require
 
 import (
 	assert "github.com/stretchr/testify/assert"
+	io "io"
 	http "net/http"
 	url "net/url"
 	time "time"
@@ -488,11 +489,11 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in
 //  assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+	if assert.HTTPBodyContains(t, handler, method, url, values, body, str, msgAndArgs...) {
 		return
 	}
 	t.FailNow()
@@ -504,11 +505,11 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s
 //  assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+	if assert.HTTPBodyContainsf(t, handler, method, url, values, body, str, msg, args...) {
 		return
 	}
 	t.FailNow()
@@ -520,11 +521,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
 //  assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+	if assert.HTTPBodyNotContains(t, handler, method, url, values, body, str, msgAndArgs...) {
 		return
 	}
 	t.FailNow()
@@ -536,11 +537,11 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur
 //  assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
 	if h, ok := t.(tHelper); ok {
 		h.Helper()
 	}
-	if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+	if assert.HTTPBodyNotContainsf(t, handler, method, url, values, body, str, msg, args...) {
 		return
 	}
 	t.FailNow()
diff --git a/require/require_forward.go b/require/require_forward.go
index b556d5d..8a7165a 100644
--- a/require/require_forward.go
+++ b/require/require_forward.go
@@ -7,6 +7,7 @@ package require
 
 import (
 	assert "github.com/stretchr/testify/assert"
+	io "io"
 	http "net/http"
 	url "net/url"
 	time "time"
@@ -386,11 +387,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
 //  a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+	HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
 }
 
 // HTTPBodyContainsf asserts that a specified handler returns a
@@ -399,11 +400,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
 //  a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+	HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
 }
 
 // HTTPBodyNotContains asserts that a specified handler returns a
@@ -412,11 +413,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
 //  a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+	HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
 }
 
 // HTTPBodyNotContainsf asserts that a specified handler returns a
@@ -425,11 +426,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
 //  a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
 //
 // Returns whether the assertion was successful (true) or not (false).
-func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
 	if h, ok := a.t.(tHelper); ok {
 		h.Helper()
 	}
-	HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+	HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
 }
 
 // HTTPError asserts that a specified handler returns an error status code.


Test patch:
diff --git a/assert/assertions_test.go b/assert/assertions_test.go
index 042cf68..4f0f41c 100644
--- a/assert/assertions_test.go
+++ b/assert/assertions_test.go
@@ -1306,6 +1306,7 @@ func TestInDelta(t *testing.T) {
 		a, b  interface{}
 		delta float64
 	}{
+		{uint(2), uint(1), 1},
 		{uint8(2), uint8(1), 1},
 		{uint16(2), uint16(1), 1},
 		{uint32(2), uint32(1), 1},
@@ -2087,6 +2088,12 @@ func BenchmarkBytesEqual(b *testing.B) {
 	}
 }
 
+func BenchmarkNotNil(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		NotNil(b, b)
+	}
+}
+
 func ExampleComparisonAssertionFunc() {
 	t := &testing.T{} // provided by test
 
diff --git a/assert/http_assertions_test.go b/assert/http_assertions_test.go
index 991866a..a898968 100644
--- a/assert/http_assertions_test.go
+++ b/assert/http_assertions_test.go
@@ -2,8 +2,10 @@ package assert
 
 import (
 	"fmt"
+	"io/ioutil"
 	"net/http"
 	"net/url"
+	"strings"
 	"testing"
 )
 
@@ -120,11 +122,6 @@ func TestHTTPStatusesWrapper(t *testing.T) {
 	assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true)
 }
 
-func httpHelloName(w http.ResponseWriter, r *http.Request) {
-	name := r.FormValue("name")
-	w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
-}
-
 func TestHTTPRequestWithNoParams(t *testing.T) {
 	var got *http.Request
 	handler := func(w http.ResponseWriter, r *http.Request) {
@@ -158,25 +155,49 @@ func TestHttpBody(t *testing.T) {
 	assert := New(t)
 	mockT := new(testing.T)
 
-	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
-	assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
-	assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+	assert.True(HTTPBodyContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "Hello, World!"))
+	assert.True(HTTPBodyContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "World"))
+	assert.False(HTTPBodyContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "world"))
 
-	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
-	assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
-	assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+	assert.False(HTTPBodyNotContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "Hello, World!"))
+	assert.False(HTTPBodyNotContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "World"))
+	assert.True(HTTPBodyNotContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "world"))
+
+	assert.True(HTTPBodyContains(mockT, httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "Hello, World!"))
+
+	body := strings.NewReader("I will get this request body back as response!!")
+	assert.True(HTTPBodyContains(mockT, httpPostHandler, "POST", "/", nil, body, "I will get this request body back as response!!"))
+	assert.True(HTTPBodyNotContains(mockT, httpPostHandler, "POST", "/", nil, body, "world"))
 }
 
 func TestHttpBodyWrappers(t *testing.T) {
 	assert := New(t)
 	mockAssert := New(new(testing.T))
 
-	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
-	assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
-	assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+	assert.True(mockAssert.HTTPBodyContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "Hello, World!"))
+	assert.True(mockAssert.HTTPBodyContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "World"))
+	assert.False(mockAssert.HTTPBodyContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "world"))
+
+	assert.False(mockAssert.HTTPBodyNotContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "Hello, World!"))
+	assert.False(mockAssert.HTTPBodyNotContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "World"))
+	assert.True(mockAssert.HTTPBodyNotContains(httpGetHelloNameHandler, "GET", "/", url.Values{"name": []string{"World"}}, nil, "world"))
 
-	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
-	assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
-	assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+	body := strings.NewReader("I will get this request body back as response!!")
+	assert.True(mockAssert.HTTPBodyContains(httpPostHandler, "POST", "/", nil, body, "I will get this request body back as response!!"))
+	assert.True(mockAssert.HTTPBodyNotContains(httpPostHandler, "POST", "/", nil, body, "world"))
+}
+
+func httpGetHelloNameHandler(w http.ResponseWriter, r *http.Request) {
+	name := r.FormValue("name")
+	w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
+}
+
+func httpPostHandler(w http.ResponseWriter, r *http.Request) {
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		http.Error(w, "can't read body", http.StatusBadRequest)
+		return
+	}
 
+	w.Write(body)
 }
diff --git a/mock/mock_test.go b/mock/mock_test.go
index 1b681aa..cb49541 100644
--- a/mock/mock_test.go
+++ b/mock/mock_test.go
@@ -778,6 +778,7 @@ func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
 func Test_callString(t *testing.T) {
 
 	assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
+	assert.Equal(t, `Method(<nil>)`, callString("Method", []interface{}{nil}, false))
 
 }