用Lua进行猴子补丁
我有一个访问Redis的Lua程序,希望测试它的运行情况。
local function main()
  local redis = require('redis')
  -- Redis に接続
  local client = redis.connect('redis://localhost:6379/0')
  -- 値を set する
  client:set('test_key', 'test_value')
  -- 値を get する
  local result = client:get('test_key')
  return result
end
return main
在Redis未启动的开发环境中,我们尝试通过下面的测试程序(test1.lua)来调用上述函数。
local function test()
  local main = require('main')
  print(main())
end
test()
执行时发生了如下错误。
似乎在redis.connect函数中无法连接到Redis出现了错误。
$ lua test1.lua
lua: /usr/local/share/lua/5.3/redis.lua:764: could not connect to localhost:6379 [closed]
stack traceback:
        [C]: in function 'error'
        /usr/local/share/lua/5.3/redis.lua:802: in function 'redis.error'
        /usr/local/share/lua/5.3/redis.lua:764: in function </usr/local/share/lua/5.3/redis.lua:760>
        (...tail calls...)
        /usr/local/share/lua/5.3/redis.lua:836: in function 'redis.connect'
        ./main.lua:4: in function 'main'
        test1.lua:3: in local 'test'
        test1.lua:5: in main chunk
        [C]: in ?
我已经将这个程序做出以下的修改。
local function test()
  local redis = require('redis')
  -- redis.connect 関数をオーバーライドして、Redis に接続しないように変更
  redis.connect = function()
    return {
      -- set したときの動作を定義
      set = function(self, key, value)
        print(string.format('[debug] set called (key: %s, value: %s)', key, value))
      end,
      -- get したときの動作を定義
      get = function(self, key)
        print(string.format('[debug] get called (key: %s)', key))
        return 'injected value'
      end,
    }
  end
  local main = require('main')
  print(main())
end
test()
这个程序可以在不启动 Redis 的情况下运行。
$ lua test2.lua
[debug] set called (key: test_key, value: test_value)
[debug] get called (key: test_key)
injected value
在Redis不可用的环境中进行测试时,这种方法似乎很方便。
使用Monkey Patch代码在生产环境中可能会引发意外的副作用和错误,因此最好不要在正式环境中使用这样的代码。