ó J9•Qc@s`dZddlZddlZddlmZyddlmZWn!ek reddlmZnXddgZddl m Z de fd „ƒYZ ydd l mZe ZWnek rËeZnXde fd „ƒYZd e fd „ƒYZd„Zd„Zd„Zd„Zd„Zd„Zd„Zedkr\ddlZejƒndS(sn Testing Plugins =============== The plugin interface is well-tested enough to safely unit test your use of its hooks with some level of confidence. However, there is also a mixin for unittest.TestCase called PluginTester that's designed to test plugins in their native runtime environment. Here's a simple example with a do-nothing plugin and a composed suite. >>> import unittest >>> from nose.plugins import Plugin, PluginTester >>> class FooPlugin(Plugin): ... pass >>> class TestPluginFoo(PluginTester, unittest.TestCase): ... activate = '--with-foo' ... plugins = [FooPlugin()] ... def test_foo(self): ... for line in self.output: ... # i.e. check for patterns ... pass ... ... # or check for a line containing ... ... assert "ValueError" in self.output ... def makeSuite(self): ... class TC(unittest.TestCase): ... def runTest(self): ... raise ValueError("I hate foo") ... return unittest.TestSuite([TC()]) ... >>> res = unittest.TestResult() >>> case = TestPluginFoo('test_foo') >>> _ = case(res) >>> res.errors [] >>> res.failures [] >>> res.wasSuccessful() True >>> res.testsRun 1 And here is a more complex example of testing a plugin that has extra arguments and reads environment variables. >>> import unittest, os >>> from nose.plugins import Plugin, PluginTester >>> class FancyOutputter(Plugin): ... name = "fancy" ... def configure(self, options, conf): ... Plugin.configure(self, options, conf) ... if not self.enabled: ... return ... self.fanciness = 1 ... if options.more_fancy: ... self.fanciness = 2 ... if 'EVEN_FANCIER' in self.env: ... self.fanciness = 3 ... ... def options(self, parser, env=os.environ): ... self.env = env ... parser.add_option('--more-fancy', action='store_true') ... Plugin.options(self, parser, env=env) ... ... def report(self, stream): ... stream.write("FANCY " * self.fanciness) ... >>> class TestFancyOutputter(PluginTester, unittest.TestCase): ... activate = '--with-fancy' # enables the plugin ... plugins = [FancyOutputter()] ... args = ['--more-fancy'] ... env = {'EVEN_FANCIER': '1'} ... ... def test_fancy_output(self): ... assert "FANCY FANCY FANCY" in self.output, ( ... "got: %s" % self.output) ... def makeSuite(self): ... class TC(unittest.TestCase): ... def runTest(self): ... raise ValueError("I hate fancy stuff") ... return unittest.TestSuite([TC()]) ... >>> res = unittest.TestResult() >>> case = TestFancyOutputter('test_fancy_output') >>> _ = case(res) >>> res.errors [] >>> res.failures [] >>> res.wasSuccessful() True >>> res.testsRun 1 iÿÿÿÿN(twarn(tStringIOt PluginTestertrun(tgetpidtMultiProcessFilecBsPeZdZd„Zd„Zd„Zd„Zdd„Zd„Zd„Z RS( s\ helper for testing multiprocessing multiprocessing poses a problem for doctests, since the strategy of replacing sys.stdout/stderr with file-like objects then inspecting the results won't work: the child processes will write to the objects, but the data will not be reflected in the parent doctest-ing process. The solution is to create file-like objects which will interact with multiprocessing in a more desirable way. All processes can write to this object, but only the creator can read. This allows the testing system to see a unified picture of I/O. cCs7tƒ|_tƒjƒ|_tƒ|_d|_dS(Ni(Rt_MultiProcessFile__mastertManagertQueuet_MultiProcessFile__queueRt_MultiProcessFile__buffert softspace(tself((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt__init__~s  cCsÑtƒ|jkrdSddlm}ddlm}|tƒ}x]tr¡y|jj ƒ\}}Wn|k rxPnX|dkrŽd}n||c|7>> import unittest >>> class SomeTest(unittest.TestCase): ... def runTest(self): ... raise ValueError("Now do something, plugin!") ... >>> unittest.TestSuite([SomeTest()]) # doctest: +ELLIPSIS ]> N(tNotImplementedError(R ((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt makeSuiteÝsc CsÙddlm}ddlm}ddlm}d }tƒ}|d|jd|d|d|j ƒƒ}|j d k r‡|j |_ n|j sŸ|j ƒ}n|d|j d |d |d tƒ|_t|ƒ|_d S( s7execute the plugin on the internal test suite. iÿÿÿÿ(tConfig(t TestProgram(t PluginManagertenvtstreamtpluginstargvtconfigtsuitetexitN(t nose.configR+t nose.coreR,tnose.plugins.managerR-tNonetBufferR.R0t ignoreFilest suitepathR*R1tFalsetnosetAccessDecoratortoutput(R R+R,R-R3R/tconf((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt _execPluginñs   cCs^d|jg|_|jr1|jj|jƒn|jrP|jj|jƒn|jƒdS(sUruns nosetests with the specified test suite, all plugins activated. t nosetestsN(tactivateR1targstextendR;tappendRA(R ((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytsetUps   N(R&R'R(R8RCR;RDR.R1R0R:R*RARG(((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyR³s!  R>cBs8eZdZdZd„Zd„Zd„Zd„ZRS(cCs6||_|jdƒ|jƒ|_|jdƒdS(Ni(R/Rtreadt_buf(R R/((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyR s  cCs ||jkS(N(RI(R tval((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt __contains__scCs t|jƒS(N(titerR/(R ((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyRscCs|jS(N(RI(R ((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt__str__sN( R&R'R8R/RIR RKRRM(((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyR>s    ccs‘g}xm|jtƒD]\}|j|ƒ|jƒ}| s[|jdƒr|jdƒ rdj|ƒVg}qqW|rdj|ƒVndS(s9a bunch of === characters is also considered a blank lines===t=tN(t splitlinesRRFtstript startswithtjoin(ttexttblocktline((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytblankline_separated_blocks#s  & cCsftjdtjtjBtjBƒ}g}x-t|ƒD]}|j|jd|ƒƒq6Wdj|ƒS(NsD # Grab the traceback header. Different versions of Python have # said different things on the first traceback line. ^(?P Traceback\ \( (?: most\ recent\ call\ last | innermost\ last ) \) : ) \s* $ # toss trailing whitespace on the header. (?P .*?) # don't blink: absorb stuff until... ^(?=\w) # a line *starts* with alphanum. .*?(?P \w+ ) # exception name (?P [:\n] .*) # the rest s"\g\n...\n\g\gRO( tretcompiletVERBOSEt MULTILINEtDOTALLRWRFtsubRS(toutt traceback_retblocksRU((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytremove_stack_traces0s  cCs,tjdtjtjBƒ}|jd|ƒS(Nsü # Cut the file and line no, up to the warning name ^.*:\d+:\s (?P\w+): \s+ # warning category (?P.+) $ \n? # warning message ^ .* $ # stack frame s\g: \g(RXRYRZR[R](R^twarn_re((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytsimplify_warningsFscCstjdd|ƒS(NsRan (\d+ tests?) in [0-9.]+ssRan \1 in ...s(RXR](R^((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytremove_timingsQscCs.t|ƒ}t|ƒ}t|ƒ}|jƒS(s6Modify nose output to make it easy to use in doctests.(RaRcRdRQ(R^((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pytmunge_nose_output_for_doctestVs   c Ossddlm}ddlm}ddlm}tƒ}d|kr¦|jdgƒ}t|t ƒrx|d|ƒ}n|jdiƒ}|d|d|ƒ|dRWRaRcRdReRRrR&tdoctestttestmod(((s;/sys/lib/python2.7/site-packages/nose/plugins/plugintest.pyt`s6    ?   `    <