By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,536 Members | 2,165 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,536 IT Pros & Developers. It's quick & easy.

Python automatic testing: mocking an imported module?

P: n/a
Heyas

So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed. We want our tester.py to test the code for testee.py
without changing the code for testee.py. testee.py has a module in it
that we want to mock in some tests and in others use the real module.

/foo.py: (real module)
class bar:
def __init__(self):
"I am real"

/foo_fake/foo.py: (fake module)
class bar:
def ___init__(self):
"I am a banana"

/testee.py:
import foo
foo.bar()

/tester.py:
from foo_fake import foo
foo.bar() # prints I am a banana
testee.py # also prints I am a banana
import foo
foo.bar() # prints I am real
testee.py # also prints I am real
This isnt working as we would like, does anyone have any tips on how
to get something like this working?

Mar 27 '07 #1
Share this Question
Share on Google+
6 Replies


P: n/a
On Mar 27, 6:18 pm, "Silfheed" <silfh...@gmail.comwrote:
Heyas

So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed. We want our tester.py to test the code for testee.py
without changing the code for testee.py. testee.py has a module in it
that we want to mock in some tests and in others use the real module.
I think you mean "testee.py *imports* a module", rather than "has a
module in it". Semantics but I was thrown off by this at first.

Why not write tests for the module that testee.py imports (here called
"foo.py")? If you write out the tests and foo.py passes to spec, then
you should feel confident it will work correctly with testee.py. Never
trust it; always play paranoid coder, but feel comfortable enough
using it.

After all, why should you feel comfortable using modules in the
standard library? Nobody guarantees bugs don't still lurk in there
(heck, c.l.p just found one in pdb today), however, they have unit
tests out the wazzoo that demonstrate, to the best of our knowledge,
the module works to spec. If that approach is good enough for the
standard library, wouldn't it be good enough for you?

Chris

Mar 28 '07 #2

P: n/a
"Silfheed" <si******@gmail.comwrites:
So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed.
This is sometimes called the "module under test". I wish there was a
more succinct name in common usage.
We want our tester.py to test the code for testee.py
without changing the code for testee.py.
This is called a "unit test" for the module.
testee.py has a module in it
Looking at your example, testee.py *imports* a module; it doesn't
contain another one.
that we want to mock in some tests and in othemodule.
Excellent idea.
===== foo.py =====
class Bar(object):
def __init__(self):
self.name = "bar"
=====

===== dostuff.py =====
import foo

def get_bar():
return foo.Bar()
=====

===== test_dostuff.py =====
import dostuff

class Mock_foo_module(object):
""" Mock object for foo module """

class Bar(object):
def __init__(self):
self.name = "banana"

def test_dostuff_get_bar_should_create_bar():
""" The dostuff.get_bar function should create a new Bar """
dostuff.foo = Mock_foo_module()
test_bar = dostuff.get_bar()
if not test_bar.name == "banana":
raise AssertionError("test_bar.name should be banana")
=====

This is simply using an instance of a class (Mock_foo_module) to be a
mock 'module' object. That mock module has the required 'Bar'
attribute, bound to a class; so the 'dostuff' module's 'foo' attribute
can be replaced with our mock module object for the purpose of the
test.

The mock module's Bar class behaves in an idiomatic way (setting the
'name' attribute of its instance to a known value) that we use to
check whether the 'dostuff' module actually used our mock module.

This can be extended to mock any module interface you like, and then
confirm that the module under test has actually used the module as
expected.

--
\ "A politician is an animal which can sit on a fence and yet |
`\ keep both ears to the ground." -- Henry L. Mencken |
_o__) |
Ben Finney
Mar 28 '07 #3

P: n/a
Silfheed wrote:
So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed. We want our tester.py to test the code for testee.py
without changing the code for testee.py. testee.py has a module in it
that we want to mock in some tests and in others use the real module.

/foo.py: (real module)
class bar:
def __init__(self):
"I am real"

/foo_fake/foo.py: (fake module)
class bar:
def ___init__(self):
"I am a banana"

/testee.py:
import foo
foo.bar()

/tester.py:
from foo_fake import foo
foo.bar() # prints I am a banana
testee.py # also prints I am a banana
import foo
foo.bar() # prints I am real
testee.py # also prints I am real
This isnt working as we would like, does anyone have any tips on how
to get something like this working?
You can put foo_fake.foo into sys.modules as foo:

import sys
from foo_fake import foo

assert "foo" not in sys.modules
sys.modules["foo"] = foo

foo.bar() # prints I am a banana
import foo
foo.bar() # prints I am a banana

Peter

Mar 28 '07 #4

P: n/a

"Silfheed" <si******@gmail.comwrote in message
news:11**********************@l77g2000hsb.googlegr oups.com...
Heyas

So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed. We want our tester.py to test the code for testee.py
without changing the code for testee.py. testee.py has a module in it
that we want to mock in some tests and in others use the real module.

/foo.py: (real module)
class bar:
def __init__(self):
"I am real"

/foo_fake/foo.py: (fake module)
class bar:
def ___init__(self):
"I am a banana"

/testee.py:
import foo
foo.bar()

/tester.py:
from foo_fake import foo
foo.bar() # prints I am a banana
testee.py # also prints I am a banana
import foo
foo.bar() # prints I am real
testee.py # also prints I am real
This isnt working as we would like, does anyone have any tips on how
to get something like this working?
If you add the foo_fake directory to the front of sys.path, "import foo"
will import the foo.py in foo_fake directory before the one in the local
directory.

# unverified code
import sys
sys.path.append(0,'foo_fake') # add foo_fake to front of path
import foo
foo.bar()
execfile('testee.py')
sys.path.pop(0) # remove foo_fake
reload(foo)
foo.bar()
execfile('testee.py')

-Mark

Mar 28 '07 #5

P: n/a
On Mar 27, 9:13 pm, "Chris Lasher" <chris.las...@gmail.comwrote:
On Mar 27, 6:18 pm, "Silfheed" <silfh...@gmail.comwrote:
Heyas
So we have the following situation: we have a testee.py that we want
to automatically test out and verifiy that it is worthy of being
deployed. We want our tester.py to test the code for testee.py
without changing the code for testee.py. testee.py has a module in it
that we want to mock in some tests and in others use the real module.

I think you mean "testee.py *imports* a module", rather than "has a
module in it". Semantics but I was thrown off by this at first.

Why not write tests for the module that testee.py imports (here called
"foo.py")? If you write out the tests and foo.py passes to spec, then
you should feel confident it will work correctly with testee.py. Never
trust it; always play paranoid coder, but feel comfortable enough
using it.

After all, why should you feel comfortable using modules in the
standard library? Nobody guarantees bugs don't still lurk in there
(heck, c.l.p just found one inpdbtoday),
A slight correction. At present it looks like the bug is in Python,
and its handling after setting the current frame's f_lineno when it
refers to byte code offset 0, not pdb. And if you scan c.l.p for
another oddity in pdb with respect to tracebacks, there is possibly
another bug in Python (not strictly pdb).
however, they have unit
tests out the wazzoo that demonstrate, to the best of our knowledge,
the module works to spec.
Actually, as far as I know pdb *doesn't* have any unit tests! (pydb
does though ;-)

But all this nit-picking aside, I do agree with what you have to say
most whole heartedly. (And I'd say maybe a couple more unit tests for
Python to cover these bugs are in order.)
If that approach is good enough for the
standard library, wouldn't it be good enough for you?

Chris

Mar 29 '07 #6

P: n/a
Wow, that works great! Thanks all!

On Mar 28, 12:02 am, Ben Finney <bignose+hates-s...@benfinney.id.au>
wrote:
"Silfheed" <silfh...@gmail.comwrites:
===== foo.py =====
class Bar(object):
def __init__(self):
self.name = "bar"
=====

===== dostuff.py =====
import foo

def get_bar():
return foo.Bar()
=====

===== test_dostuff.py =====
import dostuff

class Mock_foo_module(object):
""" Mock object for foo module """

class Bar(object):
def __init__(self):
self.name = "banana"

def test_dostuff_get_bar_should_create_bar():
""" The dostuff.get_bar function should create a new Bar """
dostuff.foo = Mock_foo_module()
test_bar = dostuff.get_bar()
if not test_bar.name == "banana":
raise AssertionError("test_bar.name should be banana")
=====

This is simply using an instance of a class (Mock_foo_module) to be a
mock 'module' object. That mock module has the required 'Bar'
attribute, bound to a class; so the 'dostuff' module's 'foo' attribute
can be replaced with our mock module object for the purpose of the
test.

The mock module's Bar class behaves in an idiomatic way (setting the
'name' attribute of its instance to a known value) that we use to
check whether the 'dostuff' module actually used our mock module.

This can be extended to mock any module interface you like, and then
confirm that the module under test has actually used the module as
expected.

--
\ "A politician is an animal which can sit on a fence and yet |
`\ keep both ears to the ground." -- Henry L. Mencken |
_o__) |
Ben Finney

Mar 30 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.