@@ -12,6 +12,7 @@ import (
12
12
"strconv"
13
13
"strings"
14
14
"sync"
15
+ "testing"
15
16
16
17
"github.com/jarcoal/httpmock/internal"
17
18
)
@@ -1096,10 +1097,17 @@ var oldClientsLock sync.Mutex
1096
1097
// To enable mocks for a test, simply activate at the beginning of a test:
1097
1098
//
1098
1099
// func TestFetchArticles(t *testing.T) {
1099
- // httpmock.Activate()
1100
+ // httpmock.Activate(t )
1100
1101
// // all http requests using http.DefaultTransport will now be intercepted
1101
1102
// }
1102
1103
//
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
+ //
1103
1111
// If you want all of your tests in a package to be mocked, just call
1104
1112
// [Activate] from init():
1105
1113
//
@@ -1113,7 +1121,7 @@ var oldClientsLock sync.Mutex
1113
1121
// httpmock.Activate()
1114
1122
// os.Exit(m.Run())
1115
1123
// }
1116
- func Activate () {
1124
+ func Activate (t ... testing. TB ) {
1117
1125
if Disabled () {
1118
1126
return
1119
1127
}
@@ -1124,18 +1132,30 @@ func Activate() {
1124
1132
InitialTransport = http .DefaultTransport
1125
1133
}
1126
1134
1135
+ if len (t ) > 0 && t [0 ] != nil {
1136
+ t [0 ].Cleanup (DeactivateAndReset )
1137
+ }
1138
+
1127
1139
http .DefaultTransport = DefaultTransport
1128
1140
}
1129
1141
1130
1142
// 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:
1133
1149
//
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:
1136
1155
//
1137
- // client := &http.Client{Transport: &http.Transport{TLSHandshakeTimeout: 60 * time.Second}}
1138
1156
// httpmock.ActivateNonDefault(client)
1157
+ //
1158
+ // See also [DeactivateNonDefault], [Deactivate] and [DeactivateAndReset].
1139
1159
func ActivateNonDefault (client * http.Client ) {
1140
1160
if Disabled () {
1141
1161
return
@@ -1150,63 +1170,56 @@ func ActivateNonDefault(client *http.Client) {
1150
1170
client .Transport = DefaultTransport
1151
1171
}
1152
1172
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.
1158
1176
//
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
+ }
1175
1182
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
+ }
1180
1189
}
1181
1190
1182
1191
// Deactivate shuts down the mock environment. Any HTTP calls made
1183
1192
// after this will use a live transport.
1184
1193
//
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:
1187
1196
//
1188
1197
// func TestFetchArticles(t *testing.T) {
1189
1198
// httpmock.Activate()
1190
- // defer httpmock.Deactivate( )
1199
+ // t.Cleanup( httpmock.Deactivate)
1191
1200
//
1192
1201
// // when this test ends, the mock environment will close
1193
1202
// }
1194
1203
//
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.
1200
1208
//
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.
1203
1213
//
1204
- // useful in test helpers to save your callers from calling defer themselves .
1214
+ // See also [Reset] and [DeactivateAndReset] .
1205
1215
func Deactivate () {
1206
1216
if Disabled () {
1207
1217
return
1208
1218
}
1209
- http .DefaultTransport = InitialTransport
1219
+
1220
+ if InitialTransport != nil {
1221
+ http .DefaultTransport = InitialTransport
1222
+ }
1210
1223
1211
1224
// reset the custom clients to use their original RoundTripper
1212
1225
oldClientsLock .Lock ()
@@ -1219,24 +1232,72 @@ func Deactivate() {
1219
1232
1220
1233
// Reset removes any registered mocks and returns the mock
1221
1234
// environment to its initial state. It zeroes call counters too.
1235
+ //
1236
+ // See also [DeactivateAndReset].
1222
1237
func Reset () {
1223
1238
DefaultTransport .Reset ()
1224
1239
}
1225
1240
1226
- // ZeroCallCounters zeroes call counters without touching registered responders.
1227
- func ZeroCallCounters () {
1228
- DefaultTransport .ZeroCallCounters ()
1229
- }
1230
-
1231
1241
// DeactivateAndReset is just a convenience method for calling
1232
1242
// [Deactivate] and then [Reset].
1233
1243
//
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].
1235
1262
func DeactivateAndReset () {
1236
1263
Deactivate ()
1237
1264
Reset ()
1238
1265
}
1239
1266
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
+
1240
1301
// RegisterMatcherResponder adds a new responder, associated with a given
1241
1302
// HTTP method, URL (or path) and [Matcher].
1242
1303
//
@@ -1310,8 +1371,8 @@ func DeactivateAndReset() {
1310
1371
//
1311
1372
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
1312
1373
// 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.
1315
1376
//
1316
1377
// See also [RegisterResponder] if a matcher is not needed.
1317
1378
//
@@ -1422,8 +1483,8 @@ func RegisterResponder(method, url string, responder Responder) {
1422
1483
//
1423
1484
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
1424
1485
// 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.
1427
1488
//
1428
1489
// See [RegisterRegexpResponder] if a matcher is not needed.
1429
1490
//
@@ -1458,7 +1519,7 @@ func RegisterRegexpMatcherResponder(method string, urlRegexp *regexp.Regexp, mat
1458
1519
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
1459
1520
// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
1460
1521
// 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.
1462
1523
func RegisterRegexpResponder (method string , urlRegexp * regexp.Regexp , responder Responder ) {
1463
1524
DefaultTransport .RegisterRegexpResponder (method , urlRegexp , responder )
1464
1525
}
@@ -1504,8 +1565,8 @@ func RegisterRegexpResponder(method string, urlRegexp *regexp.Regexp, responder
1504
1565
//
1505
1566
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
1506
1567
// 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.
1509
1570
//
1510
1571
// See also [RegisterResponderWithQuery] if a matcher is not needed.
1511
1572
//
@@ -1592,7 +1653,7 @@ func RegisterMatcherResponderWithQuery(method, path string, query any, matcher M
1592
1653
// If method is a lower-cased version of CONNECT, DELETE, GET, HEAD,
1593
1654
// OPTIONS, POST, PUT or TRACE, a panics occurs to notice the possible
1594
1655
// 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.
1596
1657
func RegisterResponderWithQuery (method , path string , query any , responder Responder ) {
1597
1658
RegisterMatcherResponderWithQuery (method , path , query , Matcher {}, responder )
1598
1659
}
0 commit comments