<div class="gmail_extra">Dear Tom and Herman,<br><br>Thank you guys for the genuine responses. They are helpful.<br><br>First, Herman:<br><br>>In a script like the one you describe, I would try to group all the<br>
> side-effecty IO related code into a single place and isolate it as<br>
> much as possible from the logic of the rest of the program. That way,<br>
> if you provide a single entry point or a wrapper for the IO code, you<br>
> will be able to easily test the flow of the program and not have to<br>
> worry about complicated mocking of built-in functions.<br><br>I am guessing you want me to create a small function that handles the logics inside the for loop (or iteritems())? <br><br><br>> for src, dest in src_dest:<br>
> if os.path.exists(src):<br>> if os.path.exists(dest):<br>> shutil.rmtree(dest)<br>> shutil.move(src, dest) # either way we will proceed to move<br>
> else:<br>> return (False, '%s does not exist!' % src)<br>> return (True, 'Success!')<br><br>By skipping, yes, I want the "else" clause of `if os.path.exists(dest)` (meaning, it doesn't exist yet). By mocking "os.path.exists" to be True, it probably will make it True throughout. In that one special test, how can I separate the patch? How can I stop the patch at a particular point? <br>
<br>> Finally, instead of using the exception system you are<br>
> bulk-catching exceptions and returning error indicators instead. As you<br>> mentioned above, this gives you the annoying requirement of figuring out every<br>
> possible exception instead of leaving it to the caller to properly handle them.<br><br>I don't want to raise any exception, that's why I returns a tuple (False, e). As a web app, rasie exception is bad. I figure it's a good idea to just return False, along with the exception indicator. It's up to the user (in this case, at the moment, me) to log that exception, and return nice error message. <br>
<br>I think you are referring to `side_effect` which I think I need to explicitly supply the actual exception, right? Is there a more general way to do the side effect (I wouldn't know all the exceptions that the method is capable of generating)?<br>
<br>I think I can do this<br><br><div style="margin-left:40px">import unittest<br>from shutil import Error<br>import shutil<br>from mock import patch<br><br>class TestSequenceFunctions(unittest.TestCase):<br> @patch.object(shutil, 'move')<br>
def test2(self, mocker):<br> import shutil<br> mocker.side_effect = Error<br> # mocker.side_effect = Exception <--- this is fine too<br> src = '/home/ted/tester/1'<br> dest = '/home/ted/tester/2'<br>
#result = shutil.move(src, dest)<br> #mocker.assert_called_with(src, dest)<br> self.assertRaises(Error, mocker, src, dest) # we can assert Exception instead of Error as well<br> <br>So what's the downside of always using `Exception` over explicit exception class such as shutill.Error? My implementation catches `Exception` so I feel like I've generalised it (Error will be caught as well).<br>
<br></div><br>Last, but not the least, mock objects supposed to mimic all the real thing, but it doesn't actually catch exception unless we supply a side-effect? I tried to minix `shutil.move(src, dest)` with dest being a directory that already exists. The real object will throw exception because dest must not already exists.<br>
<br><br>Thanks.<br><br>Ted<br><br><br><br><br><div class="gmail_quote">On Mon, Apr 23, 2012 at 10:47 PM, Tom Davis <span dir="ltr"><<a href="mailto:tom@recursivedream.com" target="_blank">tom@recursivedream.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Mon, 23 Apr 2012 18:24:49 -0400, Tu Ted wrote:<br>
> Please bear with me. Suppose I want to assert that result is in a<br>
> particular format, I might set the return value to something as (True,<br>
> 'Success')<br>
><br>
> Sample code: <a href="http://pastebin.com/VraxaKjL" target="_blank">http://pastebin.com/VraxaKjL</a><br>
><br>
> def batch_move(self, *args, **kwargs):<br>
> '''<br>
> Move a batch of files to its respective destinations.<br>
> Return type: tuple (boolean, message)<br>
> T/F , 'string' / str(exception)<br>
> '''<br>
><br>
> srcs= kwargs.get('srcs', None)<br>
> dests = kwargs.get('dests', None)<br>
><br>
> try:<br>
> if srcs and dests:<br>
> # map srcs and dests into dictionary (srcs --> keys, dests --><br>
> values)<br>
> src_dest= dict(zip(srcs, dests))<br>
><br>
> for src, dest in src_dest:<br>
> if os.path.exists(src):<br>
> if os.path.exists(dest):<br>
> shutil.rmtree(dest)<br>
> shutil.move(src, dest) # either way we will proceed to move<br>
> else:<br>
> return (False, '%s does not exist!' % src)<br>
> return (True, 'Success!')<br>
><br>
> else:<br>
> return (False, 'Something gone wrong with those kwargs...')<br>
> except Exception as e:<br>
> return (False, e)<br>
<br>
</div></div>I think you probably need src_dest.iteritems(), for starters...<br>
<div class="im"><br>
><br>
> In order to get to return (True, 'Success!'), I have<br>
><br>
> 1. patch os.path.exists with True as return value. But in one unittest I<br>
> want to skip this, how do I patch that os.path.exists?<br>
> if os.path.exists(dest): # I want to skip this<br>
> shutil.rmtree(dest)<br>
><br>
<br>
</div>If by "skip" you mean go to the "else" block, you could just configure the mock<br>
to return False instead. If by "skip" you mean you want the actual function to<br>
be called, just don't mock that test (if using a decorator) or stop the patch<br>
(if patching manually).<br>
<div class="im"><br>
><br>
><br>
> 2. How do I patch shutil.move(src, dest)? Do I just give True so it doesn't<br>
> generate error? What if I want the case it fails and caught an exception?<br>
> How do I simulate that? (I wouldn't always know which exception to catch,<br>
> the primarily reason to use Exception as e).<br>
<br>
</div>You should test every case, both success and failure. You can consult the<br>
documentation or the source for `shutil.move` in order to write tests for each<br>
failure case. In the case that neither of these are completely helpful, just try<br>
different scenarios and see what happens. Why would moves fail? Destination<br>
exists, insufficient permissions, etc.<br>
<div class="im"><br>
><br>
> 3. If I actually pass the function, does it really mean no exception caught<br>
> and it went through every single line? Or is it because I set<br>
> `mock_object.return_value = (True, 'Success!')?<br>
<br>
</div>A library like coverage.py will tell you that more easily, but if all you did<br>
was mock exists() and move(), then you could get every other line to run<br>
(presuming you had True/False cases that ultimately cover every code path).<br>
<br>
Now, there are a number of ways you're making your life more difficult by the<br>
way this function is written. First, it has to validate its arguments manually;<br>
that adds another code path (bad kwargs). Second, it couples the success of the<br>
function with the presentation of its failure; this could lead you to test<br>
oft-altered string values (which probably have no place in this function to<br>
begin with). Finally, instead of using the exception system you are<br>
bulk-catching exceptions and returning error indicators instead. As you<br>
mentioned above, this gives you the annoying requirement of figuring out every<br>
possible exception instead of leaving it to the caller to properly handle them.<br>
<div class="im"><br>
><br>
> 4. I am only using two dependencies here, do I need to patch out all the<br>
> external dependencies such as (os, sys, math, datetime) all in one? Or if<br>
> my function is using other functions (which are refactored)<br>
><br>
><br>
> def f1(*args, **kwargs):<br>
> f2(..) # use math, plot, datetime<br>
> f3(..) # use math and datetime<br>
> f4(..) # use datetime<br>
<br>
</div>You only need to patch that which you do not want to run as normal. In the<br>
example you gave, you should technically mock calls to each of f2(), f3(), and<br>
f4(), simply asserting on the values passed to them. This, of course, presumes<br>
you have written tests for each of these functions elsewhere, thus do not need<br>
to test them indirectly a second time.<br>
<div class="im"><br>
><br>
><br>
> Thanks. Sorry for the long questions. I really want to be good at writing<br>
> unittests.<br>
<br>
</div>An excellent goal to those on this list, I am sure ;)<br>
<br>
Hopefully my answers were somewhat useful...<br>
<br>
><br>
><br>
> --<br>
> Ted<br>
<br>
> _______________________________________________<br>
> testing-in-python mailing list<br>
> <a href="mailto:testing-in-python@lists.idyll.org">testing-in-python@lists.idyll.org</a><br>
> <a href="http://lists.idyll.org/listinfo/testing-in-python" target="_blank">http://lists.idyll.org/listinfo/testing-in-python</a><br>
<br>
<br>
_______________________________________________<br>
testing-in-python mailing list<br>
<a href="mailto:testing-in-python@lists.idyll.org">testing-in-python@lists.idyll.org</a><br>
<a href="http://lists.idyll.org/listinfo/testing-in-python" target="_blank">http://lists.idyll.org/listinfo/testing-in-python</a><br>
</blockquote></div><br></div>