以编程方式替换另一个模块的API [英] Programmatically replacing an API for another module

查看:53
本文介绍了以编程方式替换另一个模块的API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堆代码在一堆单元测试下运行。如果在测试的时候我可以提供更换

的功能来验证没有那些的正确的东西会被调用,这将是非常方便的。
的东西实际上被调用了,因为这些调用通常会花费很长时间来执行并做一些事情,好吧,我真的不想这样做.b $ b。


例如想象一下,你有一个例程,它需要一个filespec,生成一个

的文件列表,并将这些文件从一个位置复制到另一个位置。 (我

意识到这个例子可能是多个函数,应该是独立测试的,但请耐心等待。)你实际上并不是很好。 b $ b想要进行文件复制,但是你想确保适当调用文件副本

API。


使用win32com,我可能会然后使用win32file.CopyFile,但是从测试

代码我想用一个不同的调用替换它,一个测试函数
我提供的
。理想情况下,我可以替换整个模块,在导入被测模块后,我可以执行类似win32com =

__dict__的操作,并假设我有一个CopyFile在测试中定义的函数

模块,它会直接进入。但是,我怀疑这个

实际上并不会覆盖win32com所看到的

的另一个模块实际上会执行(而且我还没有充分理解Python的'/ b $ b执行模型)。

目前,ModuleTest.py执行来自模块导入*,然后在没有模块的模块上调用

调用。装饰。由于通常一个名为SomeClass.py的
文件只会定义SomeClass类,所以这比其他任何东西更方便。

。如果这是替换API的障碍,那么,我可以改变它。


任何见解都很有帮助,谢谢。

-tom!

I''ve got a bunch of code that runs under a bunch of unit tests. It''d
be really handy if when testing I could supply replacement
functionality to verify that the right things get called without those
things actually getting called, since frequently those calls take a
long time to execute and do things that, well, I don''t really want to
do.

E.g. imagine you''ve got a routine which takes a filespec, generates a
list of files, and copies those files from one location to another. (I
realize that this example could be multiple functions that should be
tested independently, but please bear with me.) You don''t actually
want to do the file copy, but you want to make sure that the file copy
API is appropriately called.

Using win32com, I might then use win32file.CopyFile, but from testing
code I''d like to replace that with a different call, a test function
that I supply. Ideally I could replace the whole module, after
importing the module under test, I could do something like ''win32com =
__dict__'', and assuming I had a CopyFile function defined in the test
module, it''d hook right in. However, I''m suspicious that this
wouldn''t actually override the win32com seen by the other module that
will actually do the execution (and I don''t yet understand Python''s
execution model sufficiently).

At present, ModuleTest.py does ''from Module import *'' and then makes
calls on Module without the "Module." decoration. Since typically a
file named SomeClass.py will only define the SomeClass class, this is
more of a convenience than anything. If this is a barrier to
replacing APIs, though, well, I can change it.

Any insight is helpful, thanks.
-tom!

推荐答案

汤姆我想我知道你在说什么。如果我这样做,那么我最近需要处理类似的东西。


一种方法可能是创建一个充当
您的代码和您希望使用的api whos函数。


界面将包含所有函数的包装函数

你想用。这个界面只包含你实际使用的api

函数的包装。


现在你已经创建了导入模块的界面了

你希望在界面中包含的功能。


此时你可以导入存根或真实的东西。代码

片段看起来像这样


尝试:

导入stub_api为api

除外:

导入real_api为api


def get():

返回api.get()


......................等

所以当你测试时你要确保stub_api模块是可用

到界面,尝试将成功,你将调用存根函数。如果

你没有使stub_api可用,那么try将失败,异常

将通过导入real_api来处理。在任何一种情况下,函数都可以通过使用api来调用
。因为你已经有效地重命名了什么是导入到api的



这样做的好处是你只能看到你的代码了

你要使用的api的功能。并且您正在隔离更改

只能编码到界面。


好​​的希望这会有所帮助。


史蒂夫


" Tom Plunket" < to *** @fancy.orgwrote in message

news:ag *************************** ***** @ 4ax.com ...
Tom i think i know what you are talking about. If i do then i have recently
had to deal with something similar.

One approach could be to create a module that acts as an interface between
your code and the api whos functions you wish to use.

The interface would consist of wrapper functions for all of the functions
you wish to use. This interface will only include the wrappers for the api
functions you will actually use.

Now you have created the interface you will need to import the module whose
functions you want to wrap up in the interface.

At this point you can either import a stub or the real thing. The code
snippet would look like this

try:
import stub_api as api
except:
import real_api as api

def get():
return api.get()

......................etc
So when you are testing you make sure that the stub_api module is available
to the interface, the try will succeed and you will call stub functions. If
you do not make the stub_api available then the try will fail, the exception
will be handled by importing the real_api. In either case functions will be
callable by using the api. as you have effectively renamed what is being
imported to api.

The advantages of this are that you only make visible to your code the
fuctions of the api that you are going to use. And you are isolating changes
to code to the interface only.

Ok hope this helps.

Steve

"Tom Plunket" <to***@fancy.orgwrote in message
news:ag********************************@4ax.com...

我有一堆代码在一堆单元测试下运行。如果在测试的时候我可以提供更换

的功能来验证没有那些的正确的东西会被调用,这将是非常方便的。
的东西实际上被调用了,因为这些调用通常会花费很长时间来执行并做一些事情,好吧,我真的不想这样做.b $ b。


例如想象一下,你有一个例程,它需要一个filespec,生成一个

的文件列表,并将这些文件从一个位置复制到另一个位置。 (我

意识到这个例子可能是多个函数,应该是独立测试的,但请耐心等待。)你实际上并不是很好。 b $ b想要进行文件复制,但是你想确保适当调用文件副本

API。


使用win32com,我可能会然后使用win32file.CopyFile,但是从测试

代码我想用一个不同的调用替换它,一个测试函数
我提供的
。理想情况下,我可以替换整个模块,在导入被测模块后,我可以执行类似win32com =

__dict__的操作,并假设我有一个CopyFile在测试中定义的函数

模块,它会直接进入。但是,我怀疑这个

实际上并不会覆盖win32com所看到的

的另一个模块实际上会执行(而且我还没有充分理解Python的'/ b $ b执行模型)。

目前,ModuleTest.py执行来自模块导入*,然后在没有模块的模块上调用

调用。装饰。由于通常一个名为SomeClass.py的
文件只会定义SomeClass类,所以这比其他任何东西更方便。

。如果这是替换API的障碍,那么,我可以改变它。


任何见解都很有帮助,谢谢。


-tom!
I''ve got a bunch of code that runs under a bunch of unit tests. It''d
be really handy if when testing I could supply replacement
functionality to verify that the right things get called without those
things actually getting called, since frequently those calls take a
long time to execute and do things that, well, I don''t really want to
do.

E.g. imagine you''ve got a routine which takes a filespec, generates a
list of files, and copies those files from one location to another. (I
realize that this example could be multiple functions that should be
tested independently, but please bear with me.) You don''t actually
want to do the file copy, but you want to make sure that the file copy
API is appropriately called.

Using win32com, I might then use win32file.CopyFile, but from testing
code I''d like to replace that with a different call, a test function
that I supply. Ideally I could replace the whole module, after
importing the module under test, I could do something like ''win32com =
__dict__'', and assuming I had a CopyFile function defined in the test
module, it''d hook right in. However, I''m suspicious that this
wouldn''t actually override the win32com seen by the other module that
will actually do the execution (and I don''t yet understand Python''s
execution model sufficiently).

At present, ModuleTest.py does ''from Module import *'' and then makes
calls on Module without the "Module." decoration. Since typically a
file named SomeClass.py will only define the SomeClass class, this is
more of a convenience than anything. If this is a barrier to
replacing APIs, though, well, I can change it.

Any insight is helpful, thanks.
-tom!



Tom Plunket写道:
Tom Plunket wrote:

我有一堆在一堆单元测试下运行的代码。如果在测试的时候我可以提供更换

的功能来验证没有那些的正确的东西会被调用,这将是非常方便的。
的东西实际上被调用了,因为这些调用通常会花费很长时间来执行并做一些事情,好吧,我真的不想这样做.b $ b。


例如想象一下,你有一个例程,它需要一个filespec,生成一个

的文件列表,并将这些文件从一个位置复制到另一个位置。 (我

意识到这个例子可能是多个函数,应该是独立测试的,但请耐心等待。)你实际上并不是很好。 b $ b想要进行文件复制,但是你想确保适当调用文件副本

API。


使用win32com,我可能会然后使用win32file.CopyFile,但是从测试

代码我想用一个不同的调用替换它,一个测试函数
我提供的
。理想情况下,我可以替换整个模块,在导入被测模块后,我可以执行类似win32com =

__dict__的操作,并假设我有一个CopyFile在测试中定义的函数

模块,它会直接进入。但是,我怀疑这个

实际上并不会覆盖win32com所看到的

的另一个模块实际上会执行(而且我还没有充分理解Python的'/ b $ b执行模型)。

目前,ModuleTest.py执行来自模块导入*,然后在没有模块的模块上调用

调用。装饰。由于通常一个名为SomeClass.py的
文件只会定义SomeClass类,所以这比其他任何东西更方便。

。如果这是替换API的障碍,那么,我可以改变它。


任何见解都很有帮助,谢谢。


-tom!
I''ve got a bunch of code that runs under a bunch of unit tests. It''d
be really handy if when testing I could supply replacement
functionality to verify that the right things get called without those
things actually getting called, since frequently those calls take a
long time to execute and do things that, well, I don''t really want to
do.

E.g. imagine you''ve got a routine which takes a filespec, generates a
list of files, and copies those files from one location to another. (I
realize that this example could be multiple functions that should be
tested independently, but please bear with me.) You don''t actually
want to do the file copy, but you want to make sure that the file copy
API is appropriately called.

Using win32com, I might then use win32file.CopyFile, but from testing
code I''d like to replace that with a different call, a test function
that I supply. Ideally I could replace the whole module, after
importing the module under test, I could do something like ''win32com =
__dict__'', and assuming I had a CopyFile function defined in the test
module, it''d hook right in. However, I''m suspicious that this
wouldn''t actually override the win32com seen by the other module that
will actually do the execution (and I don''t yet understand Python''s
execution model sufficiently).

At present, ModuleTest.py does ''from Module import *'' and then makes
calls on Module without the "Module." decoration. Since typically a
file named SomeClass.py will only define the SomeClass class, this is
more of a convenience than anything. If this is a barrier to
replacing APIs, though, well, I can change it.

Any insight is helpful, thanks.
-tom!



无论Python中的内容是什么,都叫做。


例子


def abc(a,b):

z = a + b

返回z

def efg(a,b ):

z = a * b

返回z

f = abc

print f(1,2)< br $>
f = efg

打印f(1,2)

只要实现完整的API,就可以替换函数

很容易与其他人在一起。注意:这也适用于班级方法。


观察:恕我直言,保持功能将非常困难

垫片更新你的REAL函数/方法。你还要测试不同的代码,而不是你正在执行的代码,这些代码几乎没有价值。


-Larry

Whatever points to something in Python is what is called.

example

def abc(a, b):
z=a+b
return z

def efg(a, b):
z=a*b
return z
f=abc
print f(1,2)
f=efg
print f(1,2)

As long as you implement the full API, you can replace functions
with others quite easily. Note: this also works with class methods.

Observation: IMHO it is going to be really hard to keep your functional
shims up to date as you change your REAL functions/methods. You also
are testing different code than you are executing which doesn''t make
the unit tests nearly as valuable.

-Larry


Larry Bates写道:
Larry Bates wrote:

无论Python中的内容是什么,都是所谓的。
Whatever points to something in Python is what is called.



正确。

Right.


f = abc

print f(1,2 )

f = efg

打印f(1,2)
f=abc
print f(1,2)
f=efg
print f(1,2)



当然。我在发帖后意识到我真正想问的是

如何更换导入的模块。史蒂夫先前的反应类似于我正在寻找的东西,虽然工作量很大。 ;)

Sure. I realized after posting that what I really wanted to ask was
how to replace an imported module. Steve''s earlier response is akin
to what I''m looking for, although with far too much work. ;)


只要您实现完整的API,就可以非常轻松地将函数替换为其他函数。注意:这也适用于类方法。
As long as you implement the full API, you can replace functions
with others quite easily. Note: this also works with class methods.



对,我可以一次更换一个功能:


import os


def my_join(* args):

return''/''。join(* args)


os.path.join = my_join


....但我想知道是否有一种直接的方式将

本地功能列表注入另一个模块。 br />

发布后我遇到的是我不知道如何获得模块范围的

__dict__;是可用的么?即我可以做

''print os.path .__ dict__'',但''print __dict__''在模块范围内结果

在一个NameError中因为__dict__未定义在那个范围。但是,如果

我能以某种方式做'os.path = local_module'',我基本上会得到我想要的b $ b。也许我可以只有my_os_path.py,并在我的测试中将
代码导入为os.path,然后其他代码会看到

os.path是已经加载而不再麻烦这样做了吗? Haven'n

尝试了它,我对答案很感兴趣,但我现在有足够的工作来支付
...用这种方式更换模块也可以确保我只是调用我打算调用的API的部分,这是一个方便的副作用。

Right, I can replace a function at a time:

import os

def my_join(*args):
return ''/''.join(*args)

os.path.join = my_join

....but I''m wondering if there''s a straight-forward way to inject the
local list of functions into another module.

What I ran into after posting is that I don''t know how to get the
__dict__ for the module''s scope; is it available? I.e. I can do
''print os.path.__dict__'', but ''print __dict__'' at module scope results
in a NameError since __dict__ is undefined at that scope. However, if
I could do ''os.path = local_module'' somehow, I''d be getting basically
what I want. Maybe I could just have a my_os_path.py, and in my test
code import it as os.path, and then the other code would see that
os.path is already loaded and not bother doing so again? Haven''t
tried it, am interested in the answer, but I do have enough to work
with for now... Replacing a module in this way also ensures that I''m
only calling the parts of the API that I intend to call, which is a
handy side-effect.


观察:恕我直言,当你改变你的REAL函数/方法时,保持你的功能将非常困难

垫片。你还要测试不同的代码,而不是你正在执行的代码,而不是单元测试几乎同样有价值的b $ b。
Observation: IMHO it is going to be really hard to keep your functional
shims up to date as you change your REAL functions/methods. You also
are testing different code than you are executing which doesn''t make
the unit tests nearly as valuable.



取决于我所嘲笑的一切。如果我在互联网上嘲笑一个昂贵的服务

连接起来很费时间,甚至可以嘲笑一个明确定义的系统API调用,同样是时间

消费来调用,然后我可以存在一些不做的事情,而不是验证参数。另外,我可以使用我的模拟记录

警告和可能错误的行为,并且

随后获得自动测试,我正在处理API错误

正确。


这些都不是功能性的垫片,这意味着它们在另外两个有趣的位置之间就位于

之间我控制下的代码。他们是功能性的叶子,这是运营链的终点。

例如我排队了我发送到数据库的所有命令

并验证它们是我打算发送的,我接受了

数据库将按照它应该解释这些命令。


感谢您的反馈,无论如何,

-tom!

Depends on what all I''m mocking. If I''m mocking an expensive service
across the internet that is time consuming to connect to, or even
mocking a well-defined system API call that is similarly time
consuming to call, then I can stub something in that doesn''t do
anything but validate the arguments. Additionally, I can "document"
the caveats and possibly-errant behavior with my mock, and
subsequently get automatic testing that I''m dealing with API bugs
properly.

These aren''t functional shims, which would imply that they sit in
between two other bits of interesting code under my control. They''re
functional leaves, which are the end point of the operational chain.
E.g. I queue up all of the commands that I''m sending to the database
and verify that they''re what I intended to send, and I accept that the
database will interpret those commands as it should.

Thanks for the feedback, regardless,
-tom!

这篇关于以编程方式替换另一个模块的API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆