@@ -12,6 +12,7 @@ import (
1212 "strconv"
1313 "strings"
1414 "sync"
15+ "testing"
1516
1617 "github.com/jarcoal/httpmock/internal"
1718)
@@ -1096,10 +1097,17 @@ var oldClientsLock sync.Mutex
10961097// To enable mocks for a test, simply activate at the beginning of a test:
10971098//
10981099// func TestFetchArticles(t *testing.T) {
1099- // httpmock.Activate()
1100+ // httpmock.Activate(t )
11001101// // all http requests using http.DefaultTransport will now be intercepted
11011102// }
11021103//
1104+ // t is optional, when present it allows to automatically call
1105+ // [DeactivateAndReset] at the end of the test. It is strictly
1106+ // equivalent to:
1107+ //
1108+ // httpmock.Activate()
1109+ // t.Cleanup(httpmock.DeactivateAndReset)
1110+ //
11031111// If you want all of your tests in a package to be mocked, just call
11041112// [Activate] from init():
11051113//
@@ -1113,7 +1121,7 @@ var oldClientsLock sync.Mutex
11131121// httpmock.Activate()
11141122// os.Exit(m.Run())
11151123// }
1116- func Activate () {
1124+ func Activate (t ... testing. TB ) {
11171125 if Disabled () {
11181126 return
11191127 }
@@ -1124,18 +1132,30 @@ func Activate() {
11241132 InitialTransport = http .DefaultTransport
11251133 }
11261134
1135+ if len (t ) > 0 && t [0 ] != nil {
1136+ t [0 ].Cleanup (DeactivateAndReset )
1137+ }
1138+
11271139 http .DefaultTransport = DefaultTransport
11281140}
11291141
11301142// ActivateNonDefault starts the mock environment with a non-default
1131- // [*http.Client]. This emulates the [Activate] function, but allows for
1132- // custom clients that do not use [http.DefaultTransport].
1143+ // [*http.Client]. This emulates the [Activate] function, but allows
1144+ // for custom clients that do not use [http.DefaultTransport]
1145+ // directly. To do so, it overrides the client Transport field with
1146+ // [DefaultTransport].
1147+ //
1148+ // To enable mocks for a test using a custom client, like:
11331149//
1134- // To enable mocks for a test using a custom client, activate at the
1135- // beginning of a test:
1150+ // transport := http.DefaultTransport.(*http.Transport).Clone()
1151+ // transport.TLSHandshakeTimeout = 60 * time.Second
1152+ // client := &http.Client{Transport: transport}
1153+ //
1154+ // activate at the beginning of the test:
11361155//
1137- // client := &http.Client{Transport: &http.Transport{TLSHandshakeTimeout: 60 * time.Second}}
11381156// httpmock.ActivateNonDefault(client)
1157+ //
1158+ // See also [DeactivateNonDefault], [Deactivate] and [DeactivateAndReset].
11391159func ActivateNonDefault (client * http.Client ) {
11401160 if Disabled () {
11411161 return
@@ -1150,63 +1170,56 @@ func ActivateNonDefault(client *http.Client) {
11501170 client .Transport = DefaultTransport
11511171}
11521172
1153- // GetCallCountInfo gets the info on all the calls httpmock has caught
1154- // since it was activated or reset. The info is returned as a map of
1155- // the calling keys with the number of calls made to them as their
1156- // value. The key is the method, a space, and the URL all concatenated
1157- // together.
1173+ // DeactivateNonDefault shuts down the mock environment for
1174+ // client. Any HTTP calls made after this will use the transport used
1175+ // before [ActivateNonDefault] call.
11581176//
1159- // As a special case, regexp responders generate 2 entries for each
1160- // call. One for the call caught and the other for the rule that
1161- // matched. For example:
1162- //
1163- // RegisterResponder("GET", `=~z\.com\z`, NewStringResponder(200, "body"))
1164- // http.Get("http://z.com")
1165- //
1166- // will generate the following result:
1167- //
1168- // map[string]int{
1169- // `GET http://z.com`: 1,
1170- // `GET =~z\.com\z`: 1,
1171- // }
1172- func GetCallCountInfo () map [string ]int {
1173- return DefaultTransport .GetCallCountInfo ()
1174- }
1177+ // See also [Deactivate] and [DeactivateAndReset].
1178+ func DeactivateNonDefault (client * http.Client ) {
1179+ if Disabled () {
1180+ return
1181+ }
11751182
1176- // GetTotalCallCount gets the total number of calls httpmock has taken
1177- // since it was activated or reset.
1178- func GetTotalCallCount () int {
1179- return DefaultTransport .GetTotalCallCount ()
1183+ oldClientsLock .Lock ()
1184+ defer oldClientsLock .Unlock ()
1185+ if tr , ok := oldClients [client ]; ok {
1186+ delete (oldClients , client )
1187+ client .Transport = tr
1188+ }
11801189}
11811190
11821191// Deactivate shuts down the mock environment. Any HTTP calls made
11831192// after this will use a live transport.
11841193//
1185- // Usually you'll call it in a defer right after activating the mock
1186- // environment:
1194+ // Usually you'll call it in a [testing.T.Cleanup] right after
1195+ // activating the mock environment:
11871196//
11881197// func TestFetchArticles(t *testing.T) {
11891198// httpmock.Activate()
1190- // defer httpmock.Deactivate( )
1199+ // t.Cleanup( httpmock.Deactivate)
11911200//
11921201// // when this test ends, the mock environment will close
11931202// }
11941203//
1195- // Since go 1.14 you can also use [*testing.T.Cleanup] method as in:
1196- //
1197- // func TestFetchArticles(t *testing.T) {
1198- // httpmock.Activate()
1199- // t.Cleanup(httpmock.Deactivate)
1204+ // Note that registered mocks and corresponding counters are not
1205+ // removed. The next time [Activate] will be called they will be
1206+ // active again. Use [DeactivateAndReset] to also remove registered
1207+ // mocks & counters.
12001208//
1201- // // when this test ends, the mock environment will close
1202- // }
1209+ // It also restores all clients Transport field previously overridden
1210+ // by [ActivateNonDefault]. Unlike globally registered mocks, these
1211+ // clients won't be mocked anymore the next time [Activate] will be
1212+ // called.
12031213//
1204- // useful in test helpers to save your callers from calling defer themselves .
1214+ // See also [Reset] and [DeactivateAndReset] .
12051215func Deactivate () {
12061216 if Disabled () {
12071217 return
12081218 }
1209- http .DefaultTransport = InitialTransport
1219+
1220+ if InitialTransport != nil {
1221+ http .DefaultTransport = InitialTransport
1222+ }
12101223
12111224 // reset the custom clients to use their original RoundTripper
12121225 oldClientsLock .Lock ()
@@ -1219,24 +1232,72 @@ func Deactivate() {
12191232
12201233// Reset removes any registered mocks and returns the mock
12211234// environment to its initial state. It zeroes call counters too.
1235+ //
1236+ // See also [DeactivateAndReset].
12221237func Reset () {
12231238 DefaultTransport .Reset ()
12241239}
12251240
1226- // ZeroCallCounters zeroes call counters without touching registered responders.
1227- func ZeroCallCounters () {
1228- DefaultTransport .ZeroCallCounters ()
1229- }
1230-
12311241// DeactivateAndReset is just a convenience method for calling
12321242// [Deactivate] and then [Reset].
12331243//
1234- // Happy deferring!
1244+ // Often called at the end of the test like in:
1245+ //
1246+ // func TestFetchArticles(t *testing.T) {
1247+ // httpmock.Activate()
1248+ // t.Cleanup(httpmock.DeactivateAndReset)
1249+ //
1250+ // // when this test ends, the mock environment will close
1251+ // }
1252+ //
1253+ // you may prefer the simpler:
1254+ //
1255+ // func TestFetchArticles(t *testing.T) {
1256+ // httpmock.Activate(t)
1257+ //
1258+ // // when this test ends, the mock environment will close
1259+ // }
1260+ //
1261+ // See [Activate].
12351262func DeactivateAndReset () {
12361263 Deactivate ()
12371264 Reset ()
12381265}
12391266
1267+ // GetCallCountInfo gets the info on all the calls httpmock has caught
1268+ // since it was activated or reset. The info is returned as a map of
1269+ // the calling keys with the number of calls made to them as their
1270+ // value. The key is the method, a space, and the URL all concatenated
1271+ // together.
1272+ //
1273+ // As a special case, regexp responders generate 2 entries for each
1274+ // call. One for the call caught and the other for the rule that
1275+ // matched. For example:
1276+ //
1277+ // RegisterResponder("GET", `=~z\.com\z`, NewStringResponder(200, "body"))
1278+ // http.Get("http://z.com")
1279+ //
1280+ // will generate the following result:
1281+ //
1282+ // map[string]int{
1283+ // `GET http://z.com`: 1,
1284+ // `GET =~z\.com\z`: 1,
1285+ // }
1286+ func GetCallCountInfo () map [string ]int {
1287+ return DefaultTransport .GetCallCountInfo ()
1288+ }
1289+
1290+ // GetTotalCallCount gets the total number of calls httpmock has taken
1291+ // since it was first activated or last reset.
1292+ func GetTotalCallCount () int {
1293+ return DefaultTransport .GetTotalCallCount ()
1294+ }
1295+
1296+ // ZeroCallCounters zeroes call counters without touching registered responders.
1297+ func ZeroCallCounters () {
1298+ DefaultTransport .ZeroCallCounters ()
1299+ }
1300+
12401301// RegisterMatcherResponder adds a new responder, associated with a given
12411302// HTTP method, URL (or path) and [Matcher].
12421303//
@@ -1310,8 +1371,8 @@ func DeactivateAndReset() {
13101371//
13111372// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
13121373// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
1313- // mistake. This panic can be disabled by setting m.DontCheckMethod to
1314- // true prior to this call.
1374+ // mistake. This panic can be disabled by setting
1375+ // [DefaultTransport].DontCheckMethod to true prior to this call.
13151376//
13161377// See also [RegisterResponder] if a matcher is not needed.
13171378//
@@ -1422,8 +1483,8 @@ func RegisterResponder(method, url string, responder Responder) {
14221483//
14231484// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
14241485// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
1425- // mistake. This panic can be disabled by setting m.DontCheckMethod to
1426- // true prior to this call.
1486+ // mistake. This panic can be disabled by setting
1487+ // [DefaultTransport].DontCheckMethod to true prior to this call.
14271488//
14281489// See [RegisterRegexpResponder] if a matcher is not needed.
14291490//
@@ -1458,7 +1519,7 @@ func RegisterRegexpMatcherResponder(method string, urlRegexp *regexp.Regexp, mat
14581519// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
14591520// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
14601521// mistake. This panic can be disabled by setting
1461- // DefaultTransport.DontCheckMethod to true prior to this call.
1522+ // [ DefaultTransport] .DontCheckMethod to true prior to this call.
14621523func RegisterRegexpResponder (method string , urlRegexp * regexp.Regexp , responder Responder ) {
14631524 DefaultTransport .RegisterRegexpResponder (method , urlRegexp , responder )
14641525}
@@ -1504,8 +1565,8 @@ func RegisterRegexpResponder(method string, urlRegexp *regexp.Regexp, responder
15041565//
15051566// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
15061567// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
1507- // mistake. This panic can be disabled by setting m.DontCheckMethod to
1508- // true prior to this call.
1568+ // mistake. This panic can be disabled by setting
1569+ // [DefaultTransport].DontCheckMethod to true prior to this call.
15091570//
15101571// See also [RegisterResponderWithQuery] if a matcher is not needed.
15111572//
@@ -1592,7 +1653,7 @@ func RegisterMatcherResponderWithQuery(method, path string, query any, matcher M
15921653// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
15931654// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
15941655// mistake. This panic can be disabled by setting
1595- // DefaultTransport.DontCheckMethod to true prior to this call.
1656+ // [ DefaultTransport] .DontCheckMethod to true prior to this call.
15961657func RegisterResponderWithQuery (method , path string , query any , responder Responder ) {
15971658 RegisterMatcherResponderWithQuery (method , path , query , Matcher {}, responder )
15981659}
0 commit comments