Problem When Unit Testing with PMock

S

steven

Hi,

Anyone was using pmock for unit testing with python? I met a problem
and hope someone to help me. For short, the pmock seems can not mock a
iterator object.

For example, the tested object is foo, who need to send message to
another object bar. So, to test the foo, I need mock a mockBar. But
the bar is a iterator, the foo use the bar in this way:

foo.method(self, bar):
for n in bar:
do somthing
...
my purpose is create a mockBar and pass this mock object to
foo.method(), but this ideal simply does not work. Python will complain
that calling on an uniteraterable object. I'v already set anything
like mockBar.expects(__iter__()) and mockBar.expects(next()).

Does anyone has some clues?

-
narke
 
T

Terry Reedy

Anyone was using pmock for unit testing with python? I met a problem
and hope someone to help me. For short, the pmock seems can not mock a
iterator object.

Why bother?

def mockit(): raise StopIteration

now pass mockit()
For example, the tested object is foo, who need to send message to
another object bar. So, to test the foo, I need mock a mockBar. But
the bar is a iterator, the foo use the bar in this way:

foo.method(self, bar):
for n in bar:
do somthing
...

To properly test the method, *also* feed it an iterator that yields a few
objects of the appropriate type. Assuming n is to be an int...

def intit(k):
for i in range(k): yield i

Terry J. Reedy
 
S

steven

def mockit(): raise StopIteration
now pass mockit()

but it behaviors differenctly when pass in a mockit() and pass in an
iterator with empty. so i think the code emulates nothing.
def intit(k):
for i in range(k): yield i

Now you mean define my own iteration without the help of pmock. but
there are still so many other methods in the iterator for pass in, i
have to mock them one by one totally manually, its boring and thats the
reason why i want pmock.
 
P

Peter Hansen

but it behaviors differenctly when pass in a mockit() and pass in an
iterator with empty. so i think the code emulates nothing.

Is it possible that what you really need is a generator function
instead of just a regular one?

def mockit():
raise StopIteration
yield None

(The presence of the yield will let the compiler generate the
proper code for this to be a generator, but it will never
actually hit the yield statement when it executes...)

Just a thought.

-Peter
 
T

Terry Reedy

This was meant to be a generator function. Peter corrected my error in
leaving out a never reached yield to make it so. My apologies. Putting if
False: yield None as the first line in the function has same effect.
but it behaviors differenctly when pass in a mockit() and pass in an
iterator with empty. so i think the code emulates nothing.

I hope Peter's addition clarifies and improves the situation. My idea
was/is that an iterator comsumer should be tested with an empty iterator.
Now you mean define my own iteration without the help of pmock.

That was also my intention above. 'mockit' was just a name, this could be
'mockintit'.
there are still so many other methods in the iterator for pass in,

I don't understand this. An iterator only has a trivial .__iter__ method
and a usually nontrivial .next method. A generator function makes it easy
to create as many iterators as you need.
have to mock them one by one totally manually, its boring and thats the
reason why i want pmock.

I am not familiar with pmock, but my impression is that mock objects are
for objects that you may not have available, such as a connection to a
database or file or instance of an umimplemented class ;-). For such
objects, the mock-ness consists in returning canned rather than actual
fetched or calculated answers. Iterators, on the other hand, are almost as
easily available as ints, lists, etc. Anything with the interator
interface and behavior *is* an interator, though you could make one yield
mock objects. Do as you wish once you understand whatever choices pmock
gives you.

Terry J. Reedy
 
S

steven

Peter,

for a object foo who need a iterator to do a job, i write test to make
sure the foo correctlly used the iterator, so a simple empty iterator
is not enough. because in the case, i need to see if or not the foo
called the iterator to get the proper data from it and do the proper
translating on them. so, the mock iterator i need should be such an
iterator which can returns be iterated out a lot of test data as i
willed.

i guess you are not familar with unit testing. we need mock objects
not because they are hard to implemented, we need them to make the
tests easy and fine.

-
narke
 
P

Peter Hansen

Peter,

for a object foo who need a iterator to do a job, i write test to make
sure the foo correctlly used the iterator, so a simple empty iterator
is not enough. because in the case, i need to see if or not the foo
called the iterator to get the proper data from it and do the proper
translating on them. so, the mock iterator i need should be such an
iterator which can returns be iterated out a lot of test data as i
willed.

See Terry's reply which referenced my posting to better understand
the point I was making.
i guess you are not familar with unit testing.

Your guess is wrong.
we need mock objects
not because they are hard to implemented, we need them to make the
tests easy and fine.

Thanks for the tutorial. :) I'm rather well acquainted
with unit testing and mock objects.

My point was merely that what Terry suggested did not act the
way I thought he was proposing that it acted, and I was
hoping to correct that. Not having actually read and understood
your entire original question, I didn't know at the time and
still don't know what you *really* need, just that Terry's
suggestion looked like a bit of a brain fart. :)

For what it's worth, I tend to be of the school that says that
overuse of mock objects is a "testing smell", and as part of
acting on that belief I avoid using generic mock objects.
Instead, I write minimal ones which are carefully customized
for a particular test, to make sure that the resulting mock
object's code clearly tells a reader of the test exactly what
it is trying to accomplish. Generic mocks, on the other hand,
tend to get overused and rarely make the tests very readable,
IMHO.

-Peter
 
S

steven

Peter,

I'm so sorry, the letter was originally wrote to Terry, not to you!
I guess Terry not very familar to unit testing because he said:

-- cut --
I am not familiar with pmock, but my impression is that mock objects
are
for objects that you may not have available, such as a connection to a
database or file or instance of an umimplemented class ;-). For such
objects, the mock-ness consists in returning canned rather than actual
fetched or calculated answers. Iterators, on the other hand, are
almost as
-- end --

and i just want to say, mocking object is a useful testing method , not
was telling a tutorial. :)


What you said about the overuse of the generic mock object is very
interesting. I did not think that before. I believe that use generic
or customized mocks is a problem of balance, so we may call it Art :)

Below is my code, you may look it to understand my original question
(sorry for the coding for i am totally a python newbie):

---------------------------------------
import unittest

from pmock import *

from mainctr import MainCtr



class MainCtrTest(unittest.TestCase):

def testProcess(self):

filePicker = MockFilePicker()

filePicker.expectedNextCalls = len(MockFilePicker.fns) + 1



rpt0 = "foo"

rpt1 = "bar"

(router0, router1) = (Mock(), Mock())

router0.expects(once()).feedIn(eq(MockFilePicker.fns))

router1.expects(once()).feedIn(eq(MockFilePicker.fns))

router0.expects(once()).deliver()

router1.expects(once()).deliver()


router0.expects(once()).getDeliveredSrcList().will(return_value(["fn0",
"fn2"]))

router1.expects(once()).getDeliveredSrcList().will(return_value([]))


router0.expects(once()).getDeliveryRpt().will(return_value(rpt0))


router1.expects(once()).getDeliveryRpt().will(return_value(rpt1))


routes = [router0, router1]

ctr = MainCtr(filePicker, routes)

ctr.process()

self.assertEquals(ctr.getProcessRpt(), [rpt0, rpt1])

filePicker.verify()

router0.verify()

router1.verify()



class MockFilePicker:

fns = ["f0", "f1", "f2"]

idx = 0

nextCalls = 0

resetCalls = 0

expectedResetCalls = 1

expectedNextCalls = 0

processedSet = set()

expectedProcessedSet = set(["fn0", "fn2"])

rememberProcessedCalls = 0

expectedRememberProcessedCalls = 1



def __iter__(self):

return self



def reset(self):

self.resetCalls += 1


def next(self):

self.nextCalls += 1

if self.idx < len(self.fns):

self.idx += 1

return self.fns[self.idx - 1]

else:

raise StopIteration



def processed(self, fn):

self.processedSet.add(fn)



def rememberProcessed(self):

self.rememberProcessedCalls += 1




def verify(self):

if self.nextCalls != self.expectedNextCalls:

raise Exception("nextCalls: " + str(self.nextCalls))

if self.resetCalls != self.expectedResetCalls:

raise Exception("resetCalls: " + str(self.resetCalls))

if self.processedSet != self.expectedProcessedSet:

raise Exception("processedSet: " + str(self.processedSet))

if self.rememberProcessedCalls !=
self.expectedRememberProcessedCalls:
raise Exception("rememberProcessedCalls: " +
str(self.rememberProcessedCalls))


if __name__ == "__main__":

unittest.main()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,609
Members
45,253
Latest member
BlytheFant

Latest Threads

Top