1from __future__ import absolute_import, division, print_function
2from _pytest.main import EXIT_NOTESTSCOLLECTED
3import pytest
4import gc
5
6
7def test_simple_unittest(testdir):
8    testpath = testdir.makepyfile("""
9        import unittest
10        class MyTestCase(unittest.TestCase):
11            def testpassing(self):
12                self.assertEqual('foo', 'foo')
13            def test_failing(self):
14                self.assertEqual('foo', 'bar')
15    """)
16    reprec = testdir.inline_run(testpath)
17    assert reprec.matchreport("testpassing").passed
18    assert reprec.matchreport("test_failing").failed
19
20
21def test_runTest_method(testdir):
22    testdir.makepyfile("""
23        import unittest
24        class MyTestCaseWithRunTest(unittest.TestCase):
25            def runTest(self):
26                self.assertEqual('foo', 'foo')
27        class MyTestCaseWithoutRunTest(unittest.TestCase):
28            def runTest(self):
29                self.assertEqual('foo', 'foo')
30            def test_something(self):
31                pass
32        """)
33    result = testdir.runpytest("-v")
34    result.stdout.fnmatch_lines("""
35        *MyTestCaseWithRunTest::runTest*
36        *MyTestCaseWithoutRunTest::test_something*
37        *2 passed*
38    """)
39
40
41def test_isclasscheck_issue53(testdir):
42    testpath = testdir.makepyfile("""
43        import unittest
44        class _E(object):
45            def __getattr__(self, tag):
46                pass
47        E = _E()
48    """)
49    result = testdir.runpytest(testpath)
50    assert result.ret == EXIT_NOTESTSCOLLECTED
51
52
53def test_setup(testdir):
54    testpath = testdir.makepyfile("""
55        import unittest
56        class MyTestCase(unittest.TestCase):
57            def setUp(self):
58                self.foo = 1
59            def setup_method(self, method):
60                self.foo2 = 1
61            def test_both(self):
62                self.assertEqual(1, self.foo)
63                assert self.foo2 == 1
64            def teardown_method(self, method):
65                assert 0, "42"
66
67    """)
68    reprec = testdir.inline_run("-s", testpath)
69    assert reprec.matchreport("test_both", when="call").passed
70    rep = reprec.matchreport("test_both", when="teardown")
71    assert rep.failed and '42' in str(rep.longrepr)
72
73
74def test_setUpModule(testdir):
75    testpath = testdir.makepyfile("""
76        values = []
77
78        def setUpModule():
79            values.append(1)
80
81        def tearDownModule():
82            del values[0]
83
84        def test_hello():
85            assert values == [1]
86
87        def test_world():
88            assert values == [1]
89        """)
90    result = testdir.runpytest(testpath)
91    result.stdout.fnmatch_lines([
92        "*2 passed*",
93    ])
94
95
96def test_setUpModule_failing_no_teardown(testdir):
97    testpath = testdir.makepyfile("""
98        values = []
99
100        def setUpModule():
101            0/0
102
103        def tearDownModule():
104            values.append(1)
105
106        def test_hello():
107            pass
108    """)
109    reprec = testdir.inline_run(testpath)
110    reprec.assertoutcome(passed=0, failed=1)
111    call = reprec.getcalls("pytest_runtest_setup")[0]
112    assert not call.item.module.values
113
114
115def test_new_instances(testdir):
116    testpath = testdir.makepyfile("""
117        import unittest
118        class MyTestCase(unittest.TestCase):
119            def test_func1(self):
120                self.x = 2
121            def test_func2(self):
122                assert not hasattr(self, 'x')
123    """)
124    reprec = testdir.inline_run(testpath)
125    reprec.assertoutcome(passed=2)
126
127
128def test_teardown(testdir):
129    testpath = testdir.makepyfile("""
130        import unittest
131        class MyTestCase(unittest.TestCase):
132            values = []
133            def test_one(self):
134                pass
135            def tearDown(self):
136                self.values.append(None)
137        class Second(unittest.TestCase):
138            def test_check(self):
139                self.assertEqual(MyTestCase.values, [None])
140    """)
141    reprec = testdir.inline_run(testpath)
142    passed, skipped, failed = reprec.countoutcomes()
143    assert failed == 0, failed
144    assert passed == 2
145    assert passed + skipped + failed == 2
146
147
148def test_teardown_issue1649(testdir):
149    """
150    Are TestCase objects cleaned up? Often unittest TestCase objects set
151    attributes that are large and expensive during setUp.
152
153    The TestCase will not be cleaned up if the test fails, because it
154    would then exist in the stackframe.
155    """
156    testpath = testdir.makepyfile("""
157        import unittest
158        class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase):
159            def setUp(self):
160                self.an_expensive_object = 1
161            def test_demo(self):
162                pass
163
164    """)
165    testdir.inline_run("-s", testpath)
166    gc.collect()
167    for obj in gc.get_objects():
168        assert type(obj).__name__ != 'TestCaseObjectsShouldBeCleanedUp'
169
170
171def test_unittest_skip_issue148(testdir):
172    testpath = testdir.makepyfile("""
173        import unittest
174
175        @unittest.skip("hello")
176        class MyTestCase(unittest.TestCase):
177            @classmethod
178            def setUpClass(self):
179                xxx
180            def test_one(self):
181                pass
182            @classmethod
183            def tearDownClass(self):
184                xxx
185    """)
186    reprec = testdir.inline_run(testpath)
187    reprec.assertoutcome(skipped=1)
188
189
190def test_method_and_teardown_failing_reporting(testdir):
191    testdir.makepyfile("""
192        import unittest, pytest
193        class TC(unittest.TestCase):
194            def tearDown(self):
195                assert 0, "down1"
196            def test_method(self):
197                assert False, "down2"
198    """)
199    result = testdir.runpytest("-s")
200    assert result.ret == 1
201    result.stdout.fnmatch_lines([
202        "*tearDown*",
203        "*assert 0*",
204        "*test_method*",
205        "*assert False*",
206        "*1 failed*1 error*",
207    ])
208
209
210def test_setup_failure_is_shown(testdir):
211    testdir.makepyfile("""
212        import unittest
213        import pytest
214        class TC(unittest.TestCase):
215            def setUp(self):
216                assert 0, "down1"
217            def test_method(self):
218                print ("never42")
219                xyz
220    """)
221    result = testdir.runpytest("-s")
222    assert result.ret == 1
223    result.stdout.fnmatch_lines([
224        "*setUp*",
225        "*assert 0*down1*",
226        "*1 failed*",
227    ])
228    assert 'never42' not in result.stdout.str()
229
230
231def test_setup_setUpClass(testdir):
232    testpath = testdir.makepyfile("""
233        import unittest
234        import pytest
235        class MyTestCase(unittest.TestCase):
236            x = 0
237            @classmethod
238            def setUpClass(cls):
239                cls.x += 1
240            def test_func1(self):
241                assert self.x == 1
242            def test_func2(self):
243                assert self.x == 1
244            @classmethod
245            def tearDownClass(cls):
246                cls.x -= 1
247        def test_teareddown():
248            assert MyTestCase.x == 0
249    """)
250    reprec = testdir.inline_run(testpath)
251    reprec.assertoutcome(passed=3)
252
253
254def test_setup_class(testdir):
255    testpath = testdir.makepyfile("""
256        import unittest
257        import pytest
258        class MyTestCase(unittest.TestCase):
259            x = 0
260            def setup_class(cls):
261                cls.x += 1
262            def test_func1(self):
263                assert self.x == 1
264            def test_func2(self):
265                assert self.x == 1
266            def teardown_class(cls):
267                cls.x -= 1
268        def test_teareddown():
269            assert MyTestCase.x == 0
270    """)
271    reprec = testdir.inline_run(testpath)
272    reprec.assertoutcome(passed=3)
273
274
275@pytest.mark.parametrize("type", ['Error', 'Failure'])
276def test_testcase_adderrorandfailure_defers(testdir, type):
277    testdir.makepyfile("""
278        from unittest import TestCase
279        import pytest
280        class MyTestCase(TestCase):
281            def run(self, result):
282                excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0)
283                try:
284                    result.add%s(self, excinfo._excinfo)
285                except KeyboardInterrupt:
286                    raise
287                except:
288                    pytest.fail("add%s should not raise")
289            def test_hello(self):
290                pass
291    """ % (type, type))
292    result = testdir.runpytest()
293    assert 'should not raise' not in result.stdout.str()
294
295
296@pytest.mark.parametrize("type", ['Error', 'Failure'])
297def test_testcase_custom_exception_info(testdir, type):
298    testdir.makepyfile("""
299        from unittest import TestCase
300        import py, pytest
301        import _pytest._code
302        class MyTestCase(TestCase):
303            def run(self, result):
304                excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0)
305                # we fake an incompatible exception info
306                from _pytest.monkeypatch import MonkeyPatch
307                mp = MonkeyPatch()
308                def t(*args):
309                    mp.undo()
310                    raise TypeError()
311                mp.setattr(_pytest._code, 'ExceptionInfo', t)
312                try:
313                    excinfo = excinfo._excinfo
314                    result.add%(type)s(self, excinfo)
315                finally:
316                    mp.undo()
317            def test_hello(self):
318                pass
319    """ % locals())
320    result = testdir.runpytest()
321    result.stdout.fnmatch_lines([
322        "NOTE: Incompatible Exception Representation*",
323        "*ZeroDivisionError*",
324        "*1 failed*",
325    ])
326
327
328def test_testcase_totally_incompatible_exception_info(testdir):
329    item, = testdir.getitems("""
330        from unittest import TestCase
331        class MyTestCase(TestCase):
332            def test_hello(self):
333                pass
334    """)
335    item.addError(None, 42)
336    excinfo = item._excinfo.pop(0)
337    assert 'ERROR: Unknown Incompatible' in str(excinfo.getrepr())
338
339
340def test_module_level_pytestmark(testdir):
341    testpath = testdir.makepyfile("""
342        import unittest
343        import pytest
344        pytestmark = pytest.mark.xfail
345        class MyTestCase(unittest.TestCase):
346            def test_func1(self):
347                assert 0
348    """)
349    reprec = testdir.inline_run(testpath, "-s")
350    reprec.assertoutcome(skipped=1)
351
352
353class TestTrialUnittest(object):
354    def setup_class(cls):
355        cls.ut = pytest.importorskip("twisted.trial.unittest")
356        # on windows trial uses a socket for a reactor and apparently doesn't close it properly
357        # https://twistedmatrix.com/trac/ticket/9227
358        cls.ignore_unclosed_socket_warning = ('-W', 'always')
359
360    def test_trial_testcase_runtest_not_collected(self, testdir):
361        testdir.makepyfile("""
362            from twisted.trial.unittest import TestCase
363
364            class TC(TestCase):
365                def test_hello(self):
366                    pass
367        """)
368        reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning)
369        reprec.assertoutcome(passed=1)
370        testdir.makepyfile("""
371            from twisted.trial.unittest import TestCase
372
373            class TC(TestCase):
374                def runTest(self):
375                    pass
376        """)
377        reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning)
378        reprec.assertoutcome(passed=1)
379
380    def test_trial_exceptions_with_skips(self, testdir):
381        testdir.makepyfile("""
382            from twisted.trial import unittest
383            import pytest
384            class TC(unittest.TestCase):
385                def test_hello(self):
386                    pytest.skip("skip_in_method")
387                @pytest.mark.skipif("sys.version_info != 1")
388                def test_hello2(self):
389                    pass
390                @pytest.mark.xfail(reason="iwanto")
391                def test_hello3(self):
392                    assert 0
393                def test_hello4(self):
394                    pytest.xfail("i2wanto")
395                def test_trial_skip(self):
396                    pass
397                test_trial_skip.skip = "trialselfskip"
398
399                def test_trial_todo(self):
400                    assert 0
401                test_trial_todo.todo = "mytodo"
402
403                def test_trial_todo_success(self):
404                    pass
405                test_trial_todo_success.todo = "mytodo"
406
407            class TC2(unittest.TestCase):
408                def setup_class(cls):
409                    pytest.skip("skip_in_setup_class")
410                def test_method(self):
411                    pass
412        """)
413        from _pytest.compat import _is_unittest_unexpected_success_a_failure
414        should_fail = _is_unittest_unexpected_success_a_failure()
415        result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning)
416        result.stdout.fnmatch_lines_random([
417            "*XFAIL*test_trial_todo*",
418            "*trialselfskip*",
419            "*skip_in_setup_class*",
420            "*iwanto*",
421            "*i2wanto*",
422            "*sys.version_info*",
423            "*skip_in_method*",
424            "*1 failed*4 skipped*3 xfailed*" if should_fail else "*4 skipped*3 xfail*1 xpass*",
425        ])
426        assert result.ret == (1 if should_fail else 0)
427
428    def test_trial_error(self, testdir):
429        testdir.makepyfile("""
430            from twisted.trial.unittest import TestCase
431            from twisted.internet.defer import Deferred
432            from twisted.internet import reactor
433
434            class TC(TestCase):
435                def test_one(self):
436                    crash
437
438                def test_two(self):
439                    def f(_):
440                        crash
441
442                    d = Deferred()
443                    d.addCallback(f)
444                    reactor.callLater(0.3, d.callback, None)
445                    return d
446
447                def test_three(self):
448                    def f():
449                        pass # will never get called
450                    reactor.callLater(0.3, f)
451                # will crash at teardown
452
453                def test_four(self):
454                    def f(_):
455                        reactor.callLater(0.3, f)
456                        crash
457
458                    d = Deferred()
459                    d.addCallback(f)
460                    reactor.callLater(0.3, d.callback, None)
461                    return d
462                # will crash both at test time and at teardown
463        """)
464        result = testdir.runpytest()
465        result.stdout.fnmatch_lines([
466            "*ERRORS*",
467            "*DelayedCalls*",
468            "*test_four*",
469            "*NameError*crash*",
470            "*test_one*",
471            "*NameError*crash*",
472            "*test_three*",
473            "*DelayedCalls*",
474            "*test_two*",
475            "*crash*",
476        ])
477
478    def test_trial_pdb(self, testdir):
479        p = testdir.makepyfile("""
480            from twisted.trial import unittest
481            import pytest
482            class TC(unittest.TestCase):
483                def test_hello(self):
484                    assert 0, "hellopdb"
485        """)
486        child = testdir.spawn_pytest(p)
487        child.expect("hellopdb")
488        child.sendeof()
489
490    def test_trial_testcase_skip_property(self, testdir):
491        testpath = testdir.makepyfile("""
492            from twisted.trial import unittest
493            class MyTestCase(unittest.TestCase):
494                skip = 'dont run'
495                def test_func(self):
496                    pass
497            """)
498        reprec = testdir.inline_run(testpath, "-s")
499        reprec.assertoutcome(skipped=1)
500
501    def test_trial_testfunction_skip_property(self, testdir):
502        testpath = testdir.makepyfile("""
503            from twisted.trial import unittest
504            class MyTestCase(unittest.TestCase):
505                def test_func(self):
506                    pass
507                test_func.skip = 'dont run'
508            """)
509        reprec = testdir.inline_run(testpath, "-s")
510        reprec.assertoutcome(skipped=1)
511
512    def test_trial_testcase_todo_property(self, testdir):
513        testpath = testdir.makepyfile("""
514            from twisted.trial import unittest
515            class MyTestCase(unittest.TestCase):
516                todo = 'dont run'
517                def test_func(self):
518                    assert 0
519            """)
520        reprec = testdir.inline_run(testpath, "-s")
521        reprec.assertoutcome(skipped=1)
522
523    def test_trial_testfunction_todo_property(self, testdir):
524        testpath = testdir.makepyfile("""
525            from twisted.trial import unittest
526            class MyTestCase(unittest.TestCase):
527                def test_func(self):
528                    assert 0
529                test_func.todo = 'dont run'
530            """)
531        reprec = testdir.inline_run(testpath, "-s", *self.ignore_unclosed_socket_warning)
532        reprec.assertoutcome(skipped=1)
533
534
535def test_djangolike_testcase(testdir):
536    # contributed from Morten Breekevold
537    testdir.makepyfile("""
538        from unittest import TestCase, main
539
540        class DjangoLikeTestCase(TestCase):
541
542            def setUp(self):
543                print ("setUp()")
544
545            def test_presetup_has_been_run(self):
546                print ("test_thing()")
547                self.assertTrue(hasattr(self, 'was_presetup'))
548
549            def tearDown(self):
550                print ("tearDown()")
551
552            def __call__(self, result=None):
553                try:
554                    self._pre_setup()
555                except (KeyboardInterrupt, SystemExit):
556                    raise
557                except Exception:
558                    import sys
559                    result.addError(self, sys.exc_info())
560                    return
561                super(DjangoLikeTestCase, self).__call__(result)
562                try:
563                    self._post_teardown()
564                except (KeyboardInterrupt, SystemExit):
565                    raise
566                except Exception:
567                    import sys
568                    result.addError(self, sys.exc_info())
569                    return
570
571            def _pre_setup(self):
572                print ("_pre_setup()")
573                self.was_presetup = True
574
575            def _post_teardown(self):
576                print ("_post_teardown()")
577    """)
578    result = testdir.runpytest("-s")
579    assert result.ret == 0
580    result.stdout.fnmatch_lines([
581        "*_pre_setup()*",
582        "*setUp()*",
583        "*test_thing()*",
584        "*tearDown()*",
585        "*_post_teardown()*",
586    ])
587
588
589def test_unittest_not_shown_in_traceback(testdir):
590    testdir.makepyfile("""
591        import unittest
592        class t(unittest.TestCase):
593            def test_hello(self):
594                x = 3
595                self.assertEqual(x, 4)
596    """)
597    res = testdir.runpytest()
598    assert "failUnlessEqual" not in res.stdout.str()
599
600
601def test_unorderable_types(testdir):
602    testdir.makepyfile("""
603        import unittest
604        class TestJoinEmpty(unittest.TestCase):
605            pass
606
607        def make_test():
608            class Test(unittest.TestCase):
609                pass
610            Test.__name__ = "TestFoo"
611            return Test
612        TestFoo = make_test()
613    """)
614    result = testdir.runpytest()
615    assert "TypeError" not in result.stdout.str()
616    assert result.ret == EXIT_NOTESTSCOLLECTED
617
618
619def test_unittest_typerror_traceback(testdir):
620    testdir.makepyfile("""
621        import unittest
622        class TestJoinEmpty(unittest.TestCase):
623            def test_hello(self, arg1):
624                pass
625    """)
626    result = testdir.runpytest()
627    assert "TypeError" in result.stdout.str()
628    assert result.ret == 1
629
630
631@pytest.mark.parametrize('runner', ['pytest', 'unittest'])
632def test_unittest_expected_failure_for_failing_test_is_xfail(testdir, runner):
633    script = testdir.makepyfile("""
634        import unittest
635        class MyTestCase(unittest.TestCase):
636            @unittest.expectedFailure
637            def test_failing_test_is_xfail(self):
638                assert False
639        if __name__ == '__main__':
640            unittest.main()
641    """)
642    if runner == 'pytest':
643        result = testdir.runpytest("-rxX")
644        result.stdout.fnmatch_lines([
645            "*XFAIL*MyTestCase*test_failing_test_is_xfail*",
646            "*1 xfailed*",
647        ])
648    else:
649        result = testdir.runpython(script)
650        result.stderr.fnmatch_lines([
651            "*1 test in*",
652            "*OK*(expected failures=1)*",
653        ])
654    assert result.ret == 0
655
656
657@pytest.mark.parametrize('runner', ['pytest', 'unittest'])
658def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner):
659    script = testdir.makepyfile("""
660        import unittest
661        class MyTestCase(unittest.TestCase):
662            @unittest.expectedFailure
663            def test_passing_test_is_fail(self):
664                assert True
665        if __name__ == '__main__':
666            unittest.main()
667    """)
668    from _pytest.compat import _is_unittest_unexpected_success_a_failure
669    should_fail = _is_unittest_unexpected_success_a_failure()
670    if runner == 'pytest':
671        result = testdir.runpytest("-rxX")
672        result.stdout.fnmatch_lines([
673            "*MyTestCase*test_passing_test_is_fail*",
674            "*1 failed*" if should_fail else "*1 xpassed*",
675        ])
676    else:
677        result = testdir.runpython(script)
678        result.stderr.fnmatch_lines([
679            "*1 test in*",
680            "*(unexpected successes=1)*",
681        ])
682
683    assert result.ret == (1 if should_fail else 0)
684
685
686@pytest.mark.parametrize('fix_type, stmt', [
687    ('fixture', 'return'),
688    ('yield_fixture', 'yield'),
689])
690def test_unittest_setup_interaction(testdir, fix_type, stmt):
691    testdir.makepyfile("""
692        import unittest
693        import pytest
694        class MyTestCase(unittest.TestCase):
695            @pytest.{fix_type}(scope="class", autouse=True)
696            def perclass(self, request):
697                request.cls.hello = "world"
698                {stmt}
699            @pytest.{fix_type}(scope="function", autouse=True)
700            def perfunction(self, request):
701                request.instance.funcname = request.function.__name__
702                {stmt}
703
704            def test_method1(self):
705                assert self.funcname == "test_method1"
706                assert self.hello == "world"
707
708            def test_method2(self):
709                assert self.funcname == "test_method2"
710
711            def test_classattr(self):
712                assert self.__class__.hello == "world"
713    """.format(fix_type=fix_type, stmt=stmt))
714    result = testdir.runpytest()
715    result.stdout.fnmatch_lines("*3 passed*")
716
717
718def test_non_unittest_no_setupclass_support(testdir):
719    testpath = testdir.makepyfile("""
720        class TestFoo(object):
721            x = 0
722
723            @classmethod
724            def setUpClass(cls):
725                cls.x = 1
726
727            def test_method1(self):
728                assert self.x == 0
729
730            @classmethod
731            def tearDownClass(cls):
732                cls.x = 1
733
734        def test_not_teareddown():
735            assert TestFoo.x == 0
736
737    """)
738    reprec = testdir.inline_run(testpath)
739    reprec.assertoutcome(passed=2)
740
741
742def test_no_teardown_if_setupclass_failed(testdir):
743    testpath = testdir.makepyfile("""
744        import unittest
745
746        class MyTestCase(unittest.TestCase):
747            x = 0
748
749            @classmethod
750            def setUpClass(cls):
751                cls.x = 1
752                assert False
753
754            def test_func1(self):
755                cls.x = 10
756
757            @classmethod
758            def tearDownClass(cls):
759                cls.x = 100
760
761        def test_notTornDown():
762            assert MyTestCase.x == 1
763    """)
764    reprec = testdir.inline_run(testpath)
765    reprec.assertoutcome(passed=1, failed=1)
766
767
768def test_issue333_result_clearing(testdir):
769    testdir.makeconftest("""
770        import pytest
771        @pytest.hookimpl(hookwrapper=True)
772        def pytest_runtest_call(item):
773            yield
774            assert 0
775    """)
776    testdir.makepyfile("""
777        import unittest
778        class TestIt(unittest.TestCase):
779            def test_func(self):
780                0/0
781    """)
782
783    reprec = testdir.inline_run()
784    reprec.assertoutcome(failed=1)
785
786
787def test_unittest_raise_skip_issue748(testdir):
788    testdir.makepyfile(test_foo="""
789        import unittest
790
791        class MyTestCase(unittest.TestCase):
792            def test_one(self):
793                raise unittest.SkipTest('skipping due to reasons')
794    """)
795    result = testdir.runpytest("-v", '-rs')
796    result.stdout.fnmatch_lines("""
797        *SKIP*[1]*test_foo.py*skipping due to reasons*
798        *1 skipped*
799    """)
800
801
802def test_unittest_skip_issue1169(testdir):
803    testdir.makepyfile(test_foo="""
804        import unittest
805
806        class MyTestCase(unittest.TestCase):
807            @unittest.skip("skipping due to reasons")
808            def test_skip(self):
809                 self.fail()
810        """)
811    result = testdir.runpytest("-v", '-rs')
812    result.stdout.fnmatch_lines("""
813        *SKIP*[1]*skipping due to reasons*
814        *1 skipped*
815    """)
816
817
818def test_class_method_containing_test_issue1558(testdir):
819    testdir.makepyfile(test_foo="""
820        import unittest
821
822        class MyTestCase(unittest.TestCase):
823            def test_should_run(self):
824                pass
825            def test_should_not_run(self):
826                pass
827            test_should_not_run.__test__ = False
828    """)
829    reprec = testdir.inline_run()
830    reprec.assertoutcome(passed=1)
831