Skip to content

Commit fb793bc

Browse files
committed
tests: Make base test class complain if there are duplicate tests
1 parent 3d7a4b2 commit fb793bc

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

tests/test_testbase.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import unittest
2+
3+
from uvloop import _testbase as tb
4+
5+
6+
class TestBaseTest(unittest.TestCase):
7+
8+
def test_duplicate_methods(self):
9+
with self.assertRaisesRegex(RuntimeError, 'duplicate test Foo.test_a'):
10+
11+
class Foo(tb.BaseTestCase):
12+
def test_a(self):
13+
pass
14+
15+
def test_b(self):
16+
pass
17+
18+
def test_a(self): # NOQA
19+
pass
20+
21+
def test_duplicate_methods_parent_1(self):
22+
class FooBase:
23+
def test_a(self):
24+
pass
25+
26+
with self.assertRaisesRegex(RuntimeError,
27+
'duplicate test Foo.test_a.*'
28+
'defined in FooBase'):
29+
30+
class Foo(FooBase, tb.BaseTestCase):
31+
def test_b(self):
32+
pass
33+
34+
def test_a(self):
35+
pass
36+
37+
def test_duplicate_methods_parent_2(self):
38+
class FooBase(tb.BaseTestCase):
39+
def test_a(self):
40+
pass
41+
42+
with self.assertRaisesRegex(RuntimeError,
43+
'duplicate test Foo.test_a.*'
44+
'defined in FooBase'):
45+
46+
class Foo(FooBase):
47+
def test_b(self):
48+
pass
49+
50+
def test_a(self):
51+
pass

uvloop/_testbase.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import asyncio
5+
import collections
56
import contextlib
67
import gc
78
import inspect
@@ -21,7 +22,46 @@ def __eq__(self, other):
2122
return bool(re.search(str(self), other, re.S))
2223

2324

24-
class BaseTestCase(unittest.TestCase):
25+
class TestCaseDict(collections.UserDict):
26+
27+
def __init__(self, name):
28+
super().__init__()
29+
self.name = name
30+
31+
def __setitem__(self, key, value):
32+
if key in self.data:
33+
raise RuntimeError('duplicate test {}.{}'.format(
34+
self.name, key))
35+
super().__setitem__(key, value)
36+
37+
38+
class BaseTestCaseMeta(type):
39+
40+
@classmethod
41+
def __prepare__(mcls, name, bases):
42+
return TestCaseDict(name)
43+
44+
def __new__(mcls, name, bases, dct):
45+
tests = set()
46+
for base in bases:
47+
for meth in dir(base):
48+
if meth.startswith('test_'):
49+
tests.add(meth)
50+
51+
for test_name in dct:
52+
if not test_name.startswith('test_'):
53+
continue
54+
for base in bases:
55+
if hasattr(base, test_name):
56+
raise RuntimeError(
57+
'duplicate test {}.{} (also defined in {} '
58+
'parent class)'.format(
59+
name, test_name, base.__name__))
60+
61+
return super().__new__(mcls, name, bases, dict(dct))
62+
63+
64+
class BaseTestCase(unittest.TestCase, metaclass=BaseTestCaseMeta):
2565

2666
def new_loop(self):
2767
raise NotImplementedError

0 commit comments

Comments
 (0)