How do you mock http?
Hello! I felt the need to mock http api (like nock in node, that is, mock http request-response itself on low-level part, leaving aside the question of what wrapper / library one uses to get to that http; in node it mocks basic http layer, here I tackled ZnClient), but struggled for a time how to grasp it. Finally I used something like this (with help of Mocketry, `1 to: 10` to mean "enough to actually be used even if there are more unrelated uses", it could as well be `1 to: 100`): ZnClient stub new willReturnValueFrom: ((1 to: 10) collect: [ :i | ZnMockClient whenRequest: [ :request | { request uri scheme. request uri authority. request uri pathPrintString. request uri query associations asSet } = { #https. 'onesignal.com'. '/api/v1/players/{1}' format: { UUID fromString36: 'Q7' }. { 'app_id' -> appId } asSet } and: [ #(GET HEAD) includes: request method ] ] thenResponse: [ :request | ZnResponse ok: (ZnEntity json: '{}') ] ]). with the help of this class (garbled utf not my fault, iceberg metacello integration does it): 'From Pharo6.0 of 13 May 2016 [Latest update: #60512] on 17 October 2017 at 12:05:38.908634 pm'! ZnClient subclass: #ZnMockClient instanceVariableNames: 'conditionBlock responseBlock' classVariableNames: '' poolDictionaries: '' category: 'Towergame-Tests'! !ZnMockClient commentStamp: 'HerbyVojcik 10/16/2017 16:43' prior: 0! I am a mock ZnClient. I am created with ZnMockClient whenRequest: whenBlock thenResponse: thenBlock. Upon execution of the request, when (whenBlock cull: request) is true, response is set to (thenBlock cull: request). Otherwise, behaviour is delegated to super.! !ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! conditionBlock ^ conditionBlock! ! !ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! responseBlock: anObject responseBlock := anObject! ! !ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! conditionBlock: anObject conditionBlock := anObject! ! !ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! responseBlock ^ responseBlock! ! !ZnMockClient methodsFor: 'private protocol' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! executeRequestResponse ^ (self conditionBlock cull: self request) ifTrue: [ response := self responseBlock cull: self request. response contents ] ifFalse: [ super executeRequestResponse ]! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! ZnMockClient class instanceVariableNames: ''! !ZnMockClient class methodsFor: 'instance creation' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! whenRequest: aBlock thenResponse: anotherBlock ^ self new conditionBlock: aBlock; responseBlock: anotherBlock; yourself! ! Question 1: Is there a better way? Question 2: If not, would ZnMockClient be good addition to Zinc itself, to ease testing for others? Herby
Herby VojÄÃk wrote:
Hello!
I felt the need to mock http api (like nock in node, that is, mock http request-response itself on low-level part, leaving aside the question of what wrapper / library one uses to get to that http; in node it mocks basic http layer, here I tackled ZnClient), but struggled for a time how to grasp it. Finally I used something like this (with help of Mocketry, `1 to: 10` to mean "enough to actually be used even if there are more unrelated uses", it could as well be `1 to: 100`):
ZnClient stub new willReturnValueFrom: ((1 to: 10) collect: [ :i | ZnMockClient whenRequest: [ :request | { request uri scheme. request uri authority. request uri pathPrintString. request uri query associations asSet } = { #https. 'onesignal.com'. '/api/v1/players/{1}' format: { UUID fromString36: 'Q7' }. { 'app_id' -> appId } asSet } and: [ #(GET HEAD) includes: request method ] ] thenResponse: [ :request | ZnResponse ok: (ZnEntity json: '{}') ] ]).
Actually, cleaned it up a bit, now I use shorter: ZnClient stub new will: [ ZnMockClient whenRequest: [ :request | request uri = ('https://onesignal.com/api/v1/players/{1}?app_id={2}' format: { UUID fromString36: 'Q7'. appId }) asZnUrl and: [ #(GET HEAD) includes: request method ] ] thenResponse: [ :request | ZnResponse ok: (ZnEntity json: '{}') ] ].
with the help of this class (garbled utf not my fault, iceberg metacello integration does it):
'From Pharo6.0 of 13 May 2016 [Latest update: #60512] on 17 October 2017 at 12:05:38.908634 pm'! ZnClient subclass: #ZnMockClient instanceVariableNames: 'conditionBlock responseBlock' classVariableNames: '' poolDictionaries: '' category: 'Towergame-Tests'! !ZnMockClient commentStamp: 'HerbyVojcik 10/16/2017 16:43' prior: 0! I am a mock ZnClient.
I am created with ZnMockClient whenRequest: whenBlock thenResponse: thenBlock.
Upon execution of the request, when (whenBlock cull: request) is true, response is set to (thenBlock cull: request). Otherwise, behaviour is delegated to super.!
!ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! conditionBlock ^ conditionBlock! !
!ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! responseBlock: anObject responseBlock := anObject! !
!ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! conditionBlock: anObject conditionBlock := anObject! !
!ZnMockClient methodsFor: 'accessing' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! responseBlock ^ responseBlock! !
!ZnMockClient methodsFor: 'private protocol' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! executeRequestResponse ^ (self conditionBlock cull: self request) ifTrue: [ response := self responseBlock cull: self request. response contents ] ifFalse: [ super executeRequestResponse ]! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
ZnMockClient class instanceVariableNames: ''!
!ZnMockClient class methodsFor: 'instance creation' stamp: 'HerbertVojÃÂÃÂk 10/17/2017 12:00:27'! whenRequest: aBlock thenResponse: anotherBlock ^ self new conditionBlock: aBlock; responseBlock: anotherBlock; yourself! !
Question 1: Is there a better way?
Question 2: If not, would ZnMockClient be good addition to Zinc itself, to ease testing for others?
Herby
participants (1)
-
Herby VojÄÃk