Failed py.test using httpretty contain redis client
Failed py.test using httpretty contain redis client
Story
I am faced with a problem that test codes failed. for example external web api should return mock data when we testing.
たとえば課金API のレスポンスなどテスト時においては HTTP Request に関しては Mock したい時ってありますよね。 そこで httpretty を使っていたら Redis を使ったテストで遭遇した問題を共有します。
What HTTPretty is
https://hub.points.com/h/i/5197678-mock-your-requests-with-httpretty
Problem & Solution
this code have problem.
import redis import httpretty r = redis.Redis() httpretty.enable() print r.ping()
I soleved like this.
import redis import httpretty r = redis.Redis() print r.ping() httpretty.enable() print r.ping()
What's happen ?
redis.client.Redis use connection if some connection has been alived.
redis.client.Redis は connection_pool にすでに connection があったらそれを再利用します
# redis-py/redis/client.py def execute_command(self, *args, **options): "Execute a command and return a parsed response" pool = self.connection_pool command_name = args[0] connection = pool.get_connection(command_name, **options)
for example:
import redis r = redis.Redis() print r.connection_pool._available_connections # [] print r.ping() # True print r.connection_pool._available_connections # [<redis.connection.Connection object at 0x210ac10>] print r.ping() # True
These connections created function from socket module. And HTTPretty replace that function to monkey patching.
そしてその connection を作る時に soket モジュールを使って connection を作っています。 HTTPretty は httpretty.enable() をした時に soket モジュールに monkey patching しています
# httpretty/core.py @classmethod def enable(cls): cls._is_enabled = True socket.socket = fakesock.socket socket._socketobject = fakesock.socket socket.SocketType = fakesock.socket socket.create_connection = create_fake_connection socket.gethostname = fake_gethostname socket.gethostbyname = fake_gethostbyname socket.getaddrinfo = fake_getaddrinfo
I added comment to earlier examle codes.
先ほどのコードでは以下の現象が起きています
import redis import httpretty r = redis.Redis() httpretty.enable() # repleaced create_socket function to mokey pattching print r.ping() # created monkey patched socket and it doesn't work
import redis import httpretty r = redis.Redis() print r.ping() # created connection by correct function httpretty.enable() # repleaced create_socket function to mokey pattching print r.ping() # use socket in r.connection_pool._available_connections
I avoid this probrem like this. preparing connection when httpretty.is_enable == False. In this case redis client use available connection Even if httpretty.is_enable == True as long as connection is alive.
というわけでソケットを作るタイミングを意識することによってこの問題を回避しました。 テストケースで私がやりたいことはこれで達成できました。めでたし。