[TIP] Unittesting command line scripts with unittest2?

holger krekel holger at merlinux.eu
Wed Jul 28 15:31:59 PDT 2010


On Wed, Jul 28, 2010 at 18:10 -0400, Jorge Vargas wrote:

> On Wed, Jul 28, 2010 at 5:38 PM, Michael Foord
> <fuzzyman at voidspace.org.uk> wrote:
> > On 28/07/2010 21:59, Jorge Vargas wrote:
> >>
> >> I started writing some tests using this skeleton.
> >>
> >> http://paste.ofcode.org/wr4JtC36nsMEWUVYPdSqj2
> >>
> >> That is doing two things
> >>
> >> 1- silencing the print statements as well as the subprocess calls
> >> 2- giving me a variable to test the output.
> >>
> > I'm afraid I don't understand what you are wanting to do. Is main() in that
> > code unittest2.main() ?
> >
> Sorry about that. I forgot the context. in this code main is my main function.
> 
> It basically does some optparse on it's own so my thinking was to set
> sys.argv for something it will expect. and then calling my code.
> 
> > I don't think that replacing sys.stdout will silence the output of
> > subprocesses. The subprocess module itself has ways of collecting output
> > though.
> >>
> it does if done in a clever way. One of the things I'm doing is
> unifying all our calls into this function:
> 
> def system(cmds):
>    subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
> 
> This way all the output gets into the same stdout/stderr variables.
> 
> >> So I have two questions, is this a good approach? is there a better
> >> way? perhaps it should be abstracted into a separate module, maybe a
> >> unittest2 plugin?
> >>
> >> Also Today I realized there is something wrong with this approach. I'm
> >> messing around with sys.argv which when called as `unit2 discover`
> >> gives some troubles. In fact after upgrading to the plugins branch of
> >> unittest2 I realized my tests are broken as sys.argv[1] will give an
> >> error. I assume this is a side effect for getopt which was removed in
> >> http://hg.python.org/unittest2/rev/0190b218cf49 therefore this is a
> >> minor incompatibility between unittest2-0.5.1 and tip.
> >>
> >
> > sys.argv will contain whatever the *original* test runner script was called
> > with. None of the unittest2 code modifies sys.argv and I don't think that
> > has changed since I stopped using getopt. If your tests depend on the
> > contents of sys.argv you can set or modify the list. (At least I'm pretty
> > sure I don't mutate sys.argv - I would consider that bad practise, feel free
> > to point it out if I am but a cursory glance doesn't show anything.)
> 
> Right, I just tested this and sys.argv defaults to /path/to/unit2 and
> the args I passed in, silly me ;)
> 
> >
> > There is a difference in the plugins branch: calling unit2 on its own (no
> > args) will launch test discovery (equivalent of `unit2 discover`), in this
> > case there will be no sys.argv[1]. Could this be what has happened?
> >
> I believe this is the problem. As the error I'm getting is IndexError,
> since sys.argv is shared then as a side effect my original code worked
> and now it stopped.
> 
> 
> Which brings me back to the original question, is this a good way of
> testing a cli script? or should I mock away the optparse part in some
> way?

What i usually do is define a main(args=None) function and set 
args to sys.argv[1:] in case it is None.  This way you can 
call "main(['status'])" from your tests and don't need to 
worry about global sys.argv settings during the test. 

best,
holger

> Perhaps I just need to replace sys.argv entirely ie: set it as
> sys.argv = ['/mock/path/to/my/script/','status']
> main() # my main function
> 
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python
> 

-- 



More information about the testing-in-python mailing list