Repository: stretchr/testify (go)

Issue:
TearDownSuite() not working with -failfast flag
To reproduce the bug, run the test below with `-failfast` flag, it will get stuck.

```go
package testsuite

import (
	"testing"

	"github.com/stretchr/testify/suite"
)

type TestSuite struct {
	suite.Suite
}

func (ts *TestSuite) TestA() {
	ts.Require().True(false)
}

func (ts *TestSuite) TestB() {
	ts.Require().True(true)
}

func (ts *TestSuite) TearDownSuite() {
}

func TestTestSuite(t *testing.T) {
	suite.Run(t, new(TestSuite))
}
```
After removing `-failfast` flag or `TearDownSuite` method, the suite fails correctly.

Versions: testify 1.15.1, go 1.13

Pull request description:
Change how tearDownAllSuite is run to aviod deadlock when running with failfast
## Summary
Fixes a deadlock when there is a failing test in a suite when run with failfast

## Changes
This commit https://github.com/stretchr/testify/commit/0d3c8ce9f8c3be984ccd5d2e3438b173ea722267 attempted to fix an ordering issue with suite teardown, but introduced a deadlock when a test fails when running with failfast.

The problem is that the sync.WaitGroup was being incremented for each test which was expected to be run, but with failfast not all of those tests were actually run. Then the first test is trying to run tearDownAllSuite after itself but waiting on the sync.WaitGroup which never wakes up.

I think we can just move the tearDownAllSuite  into a defer which will run after we have run whatever tests are going to be run, without the need for a sync.WaitGroup at all.

## Motivation
Fixes a defect

## Related issues
Closes #917 


Patch:
diff --git a/.travis.yml b/.travis.yml
index 46fdecf..f6601d0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,6 @@ sudo: false
 
 matrix:
   include:
-    - go: "1.8.x"
-    - go: "1.9.x"
     - go: "1.10.x"
     - go: "1.11.x"
       env: GO111MODULE=off
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 30fcf3d..c6df448 100644
--- a/mock/mock.go
+++ b/mock/mock.go
@@ -65,6 +65,11 @@ type Call struct {
 	// reference. It's useful when mocking methods such as unmarshalers or
 	// decoders.
 	RunFn func(Arguments)
+
+	// PanicMsg holds msg to be used to mock panic on the function call
+	//  if the PanicMsg is set to a non nil string the function call will panic
+	// irrespective of other settings
+	PanicMsg *string
 }
 
 func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
@@ -77,6 +82,7 @@ func newCall(parent *Mock, methodName string, callerInfo []string, methodArgumen
 		Repeatability:   0,
 		WaitFor:         nil,
 		RunFn:           nil,
+		PanicMsg:        nil,
 	}
 }
 
@@ -100,6 +106,18 @@ func (c *Call) Return(returnArguments ...interface{}) *Call {
 	return c
 }
 
+// Panic specifies if the functon call should fail and the panic message
+//
+//    Mock.On("DoSomething").Panic("test panic")
+func (c *Call) Panic(msg string) *Call {
+	c.lock()
+	defer c.unlock()
+
+	c.PanicMsg = &msg
+
+	return c
+}
+
 // Once indicates that that the mock should only return the value once.
 //
 //    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
@@ -392,6 +410,13 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
 		time.Sleep(call.waitTime)
 	}
 
+	m.mutex.Lock()
+	panicMsg := call.PanicMsg
+	m.mutex.Unlock()
+	if panicMsg != nil {
+		panic(*panicMsg)
+	}
+
 	m.mutex.Lock()
 	runFn := call.RunFn
 	m.mutex.Unlock()
@@ -830,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.
diff --git a/suite/suite.go b/suite/suite.go
index 8bbc7c2..b9b5d1c 100644
--- a/suite/suite.go
+++ b/suite/suite.go
@@ -7,7 +7,6 @@ import (
 	"reflect"
 	"regexp"
 	"runtime/debug"
-	"sync"
 	"testing"
 	"time"
 
@@ -84,7 +83,6 @@ func (suite *Suite) Run(name string, subtest func()) bool {
 func Run(t *testing.T, suite TestingSuite) {
 	defer failOnPanic(t)
 
-	testsSync := &sync.WaitGroup{}
 	suite.SetT(t)
 
 	var suiteSetupDone bool
@@ -96,6 +94,7 @@ func Run(t *testing.T, suite TestingSuite) {
 
 	tests := []testing.InternalTest{}
 	methodFinder := reflect.TypeOf(suite)
+	suiteName := methodFinder.Elem().Name()
 
 	for i := 0; i < methodFinder.NumMethod(); i++ {
 		method := methodFinder.Method(i)
@@ -110,35 +109,21 @@ func Run(t *testing.T, suite TestingSuite) {
 			continue
 		}
 
-		suiteName := methodFinder.Elem().Name()
-
 		if !suiteSetupDone {
 			if stats != nil {
 				stats.Start = time.Now()
 			}
 
-			defer func() {
-				if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
-					testsSync.Wait()
-					tearDownAllSuite.TearDownSuite()
-				}
-
-				if suiteWithStats, measureStats := suite.(WithStats); measureStats {
-					stats.End = time.Now()
-					suiteWithStats.HandleStats(suiteName, stats)
-				}
-			}()
-
 			if setupAllSuite, ok := suite.(SetupAllSuite); ok {
 				setupAllSuite.SetupSuite()
 			}
+
 			suiteSetupDone = true
 		}
 
 		test := testing.InternalTest{
 			Name: method.Name,
 			F: func(t *testing.T) {
-				defer testsSync.Done()
 				parentT := suite.T()
 				suite.SetT(t)
 				defer failOnPanic(t)
@@ -174,8 +159,20 @@ func Run(t *testing.T, suite TestingSuite) {
 			},
 		}
 		tests = append(tests, test)
-		testsSync.Add(1)
 	}
+	if suiteSetupDone {
+		defer func() {
+			if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
+				tearDownAllSuite.TearDownSuite()
+			}
+
+			if suiteWithStats, measureStats := suite.(WithStats); measureStats {
+				stats.End = time.Now()
+				suiteWithStats.HandleStats(suiteName, stats)
+			}
+		}()
+	}
+
 	runTests(t, tests)
 }
 


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 fcbc4f6..cb49541 100644
--- a/mock/mock_test.go
+++ b/mock/mock_test.go
@@ -486,6 +486,29 @@ func Test_Mock_Return(t *testing.T) {
 	assert.Nil(t, call.WaitFor)
 }
 
+func Test_Mock_Panic(t *testing.T) {
+
+	// make a test impl object
+	var mockedService = new(TestExampleImplementation)
+
+	c := mockedService.
+		On("TheExampleMethod", "A", "B", true).
+		Panic("panic message for example method")
+
+	require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+	call := mockedService.ExpectedCalls[0]
+
+	assert.Equal(t, "TheExampleMethod", call.Method)
+	assert.Equal(t, "A", call.Arguments[0])
+	assert.Equal(t, "B", call.Arguments[1])
+	assert.Equal(t, true, call.Arguments[2])
+	assert.Equal(t, 0, call.Repeatability)
+	assert.Equal(t, 0, call.Repeatability)
+	assert.Equal(t, "panic message for example method", *call.PanicMsg)
+	assert.Nil(t, call.WaitFor)
+}
+
 func Test_Mock_Return_WaitUntil(t *testing.T) {
 
 	// make a test impl object
@@ -755,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))
 
 }
 
@@ -1420,6 +1444,14 @@ func Test_MockMethodCalled(t *testing.T) {
 	m.AssertExpectations(t)
 }
 
+func Test_MockMethodCalled_Panic(t *testing.T) {
+	m := new(Mock)
+	m.On("foo", "hello").Panic("world panics")
+
+	require.PanicsWithValue(t, "world panics", func() { m.MethodCalled("foo", "hello") })
+	m.AssertExpectations(t)
+}
+
 // Test to validate fix for racy concurrent call access in MethodCalled()
 func Test_MockReturnAndCalledConcurrent(t *testing.T) {
 	iterations := 1000
diff --git a/suite/suite_test.go b/suite/suite_test.go
index 8b698a0..963a252 100644
--- a/suite/suite_test.go
+++ b/suite/suite_test.go
@@ -1,10 +1,13 @@
 package suite
 
 import (
+	"bytes"
 	"errors"
+	"flag"
 	"io/ioutil"
 	"math/rand"
 	"os"
+	"os/exec"
 	"strings"
 	"testing"
 	"time"
@@ -512,3 +515,75 @@ func TestSuiteWithStats(t *testing.T) {
 	assert.NotZero(t, testStats.End)
 	assert.True(t, testStats.Passed)
 }
+
+// FailfastSuite will test the behavior when running with the failfast flag
+// It logs calls in the callOrder slice which we then use to assert the correct calls were made
+type FailfastSuite struct {
+	Suite
+	callOrder []string
+}
+
+func (s *FailfastSuite) call(method string) {
+	s.callOrder = append(s.callOrder, method)
+}
+
+func TestFailfastSuite(t *testing.T) {
+	// This test suite is run twice. Once normally and once with the -failfast flag by TestFailfastSuiteFailFastOn
+	// If you need to debug it run this test directly with the failfast flag set on/off as you need
+	failFast := flag.Lookup("test.failfast").Value.(flag.Getter).Get().(bool)
+	s := new(FailfastSuite)
+	ok := testing.RunTests(
+		allTestsFilter,
+		[]testing.InternalTest{{
+			Name: "TestFailfastSuite",
+			F: func(t *testing.T) {
+				Run(t, s)
+			},
+		}},
+	)
+	assert.Equal(t, false, ok)
+	if failFast {
+		// Test A Fails and because we are running with failfast Test B never runs and we proceed straight to TearDownSuite
+		assert.Equal(t, "SetupSuite;SetupTest;Test A Fails;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
+	} else {
+		// Test A Fails and because we are running without failfast we continue and run Test B and then proceed to TearDownSuite
+		assert.Equal(t, "SetupSuite;SetupTest;Test A Fails;TearDownTest;SetupTest;Test B Passes;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
+	}
+}
+func TestFailfastSuiteFailFastOn(t *testing.T) {
+	// To test this with failfast on (and isolated from other intended test failures in our test suite) we launch it in its own process
+	cmd := exec.Command("go", "test", "-v", "-race", "-run", "TestFailfastSuite", "-failfast")
+	var out bytes.Buffer
+	cmd.Stdout = &out
+	t.Log("Running go test -v -race -run TestFailfastSuite -failfast")
+	err := cmd.Run()
+	t.Log(out.String())
+	if err != nil {
+		t.Log(err)
+		t.Fail()
+	}
+}
+func (s *FailfastSuite) SetupSuite() {
+	s.call("SetupSuite")
+}
+
+func (s *FailfastSuite) TearDownSuite() {
+	s.call("TearDownSuite")
+}
+func (s *FailfastSuite) SetupTest() {
+	s.call("SetupTest")
+}
+
+func (s *FailfastSuite) TearDownTest() {
+	s.call("TearDownTest")
+}
+
+func (s *FailfastSuite) Test_A_Fails() {
+	s.call("Test A Fails")
+	s.T().Error("Test A meant to fail")
+}
+
+func (s *FailfastSuite) Test_B_Passes() {
+	s.call("Test B Passes")
+	s.Require().True(true)
+}