Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 41981) +++ Misc/NEWS (working copy) @@ -319,6 +319,9 @@ Library ------- +- Patch #xxxxxxx: Add unittest.ShouldFail decorator for designating + test methods which should (temporarily) fail. + - Patch #1177307: Added a new codec utf_8_sig for UTF-8 with a BOM signature. - Patch #1157027: cookielib mishandles RFC 2109 cookies in Netscape mode Index: Lib/unittest.py =================================================================== --- Lib/unittest.py (revision 41981) +++ Lib/unittest.py (working copy) @@ -58,7 +58,9 @@ # Exported classes and functions ############################################################################## __all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner', - 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader'] + 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader', + 'ShouldFail', + ] # Expose obsolete functions for backwards compatibility __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) @@ -92,6 +94,14 @@ __unittest = 1 +_FAILURE_ATTR = 'fail_expected' + +# decorator for describing tests that are expected to fail +# if the method doesn't fail, that creates a failure. +def ShouldFail(func): + setattr(func, _FAILURE_ATTR, True) + return func + class TestResult: """Holder for test result information. @@ -258,9 +268,15 @@ ok = False try: testMethod() - ok = True + if hasattr(testMethod, _FAILURE_ATTR): + e = self.failureException + exc_info = (e, e('expected failure did not occur'), None) + result.addFailure(self, exc_info) + else: + ok = True except self.failureException: - result.addFailure(self, self.__exc_info()) + if not hasattr(testMethod, _FAILURE_ATTR): + result.addFailure(self, self.__exc_info()) except KeyboardInterrupt: raise except: Index: Lib/test/test_unittest.py =================================================================== --- Lib/test/test_unittest.py (revision 41981) +++ Lib/test/test_unittest.py (working copy) @@ -18,13 +18,31 @@ True """ +def test_should_fail_with_no_failure(): + """ + >>> class MyTest(unittest.TestCase): + ... @unittest.ShouldFail + ... def test_really_should_fail(self): + ... # expect a failure: if this method pass, that's a failure + ... pass + ... + >>> suite = unittest.makeSuite(MyTest) + >>> suite.run(unittest.TestResult()) + + """ +class TestUnittest(unittest.TestCase): + @unittest.ShouldFail + def test_should_fail_with_failure(self): + self.fail('boo!') + ###################################################################### ## Main ###################################################################### def test_main(): from test import test_support, test_unittest + test_support.run_unittest(TestUnittest) test_support.run_doctest(test_unittest, verbosity=True) if __name__ == '__main__': Index: Lib/test/test_compiler.py =================================================================== --- Lib/test/test_compiler.py (revision 41981) +++ Lib/test/test_compiler.py (working copy) @@ -37,6 +37,13 @@ def testNewClassSyntax(self): compiler.compile("class foo():pass\n\n","","exec") + @unittest.ShouldFail + def testSyntaxErrors(self): + # http://python.org/sf/1385040 + # default arg should not be allowed before non-default + self.assertRaises(SyntaxError, compiler.compile, + "def foo(a=1,b):pass\n\n", "", "exec") + def testLineNo(self): # Test that all nodes except Module have a correct lineno attribute. filename = __file__ @@ -65,7 +72,8 @@ self.assertEquals(flatten([1, [2]]), [1, 2]) self.assertEquals(flatten((1, (2,))), [1, 2]) -NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard) +NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard, + compiler.ast.Decorators, compiler.ast.Getattr, ) ############################################################################### # code below is just used to trigger some possible errors, for the benefit of Index: Lib/test/outstanding_bugs.py =================================================================== --- Lib/test/outstanding_bugs.py (revision 41981) +++ Lib/test/outstanding_bugs.py (working copy) @@ -1,24 +0,0 @@ -# -# This file is for everybody to add tests for bugs that aren't -# fixed yet. Please add a test case and appropriate bug description. -# -# When you fix one of the bugs, please move the test to the correct -# test_ module. -# - -import unittest -from test import test_support - -class TestBug1385040(unittest.TestCase): - def testSyntaxError(self): - import compiler - - # The following snippet gives a SyntaxError in the interpreter - # - # If you compile and exec it, the call foo(7) returns (7, 1) - self.assertRaises(SyntaxError, compiler.compile, - "def foo(a=1, b): return a, b\n\n", "", "exec") - - -def test_main(): - test_support.run_unittest(TestBug1385040) Index: Doc/lib/libunittest.tex =================================================================== --- Doc/lib/libunittest.tex (revision 41981) +++ Doc/lib/libunittest.tex (working copy) @@ -505,6 +505,21 @@ provide alternate implementations. \end{classdesc} +\begin{funcdesc}{ShouldFail}{} + Designate a test method that is (temporarily) expected to fail. + This is useful when you know about a problem, but aren't able to + fix it. If the test method does not fail, a failure will be generated. + The way to use this decorator function is: + +\begin{verbatim} +class MyTestCase(unittest.TestCase): + @unittest.ShouldFail + def test_method(self): + self.fail("I don't want to pass, just because I'm mean.") +\end{verbatim} +\versionadded{2.5} +\end{funcdesc} + \begin{funcdesc}{main}{\optional{module\optional{, defaultTest\optional{, argv\optional{, testRunner\optional{, testRunner}}}}}}