Skip to content

Commit fca4fe9

Browse files
authored
Test Suite Housekeeping (Part 3) (#1167)
* Add test fixtures exclusive for tests.providers * Pytestify tests.sphinx * Pytestify and improve user agent provider tests * Pytestify barcode provider tests * Fix flake8 bare except issue * Pytestify, reorganize, and improve Generator class tests * Pytestify, reorganize, and improve Faker class tests * Fix test failure * Pytestify currency provider tests * Pytestify isbn provider tests * Pytestify, reorganize, and improve internet provider tests * Pytestify, reorganize, and improve base provider tests * Fix CI errors
1 parent 262a5bb commit fca4fe9

13 files changed

+1000
-1136
lines changed

tests/providers/__init__.py

Lines changed: 210 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,229 @@
1-
import unittest
1+
import re
2+
import string
23

3-
from faker import Faker
4+
from collections import OrderedDict
45

6+
import pytest
57

6-
class BaseProviderTestCase(unittest.TestCase):
7-
def setUp(self):
8-
self.fake = Faker('en_US')
9-
Faker.seed(0)
8+
from faker.providers import BaseProvider
109

11-
def test_random_digit_or_empty(self):
12-
ret = self.fake.random_digit_or_empty()
13-
assert isinstance(ret, int)
14-
assert 0 <= ret <= 9
1510

16-
Faker.seed(1)
17-
assert self.fake.random_digit_or_empty() == ''
11+
class TestBaseProvider:
12+
"""Test base provider methods"""
1813

19-
def test_random_digit_not_null_or_empty(self):
20-
ret = self.fake.random_digit_not_null_or_empty()
21-
assert isinstance(ret, int)
22-
assert 0 <= ret <= 9
14+
def test_locale(self, faker, num_samples):
15+
locales = [
16+
'{}_{}'.format(language, region)
17+
for language, regions in BaseProvider.language_locale_codes.items()
18+
for region in regions
19+
]
20+
for _ in range(num_samples):
21+
locale = faker.locale()
22+
assert locale in locales
2323

24-
Faker.seed(1)
25-
assert self.fake.random_digit_not_null_or_empty() == ''
24+
def test_language_code(self, faker, num_samples):
25+
language_codes = list(BaseProvider.language_locale_codes)
26+
for _ in range(num_samples):
27+
language_code = faker.language_code()
28+
assert language_code in language_codes
2629

27-
def test_randomize_nb_elements(self):
28-
assert self.fake.randomize_nb_elements(number=1, le=True, ge=True) == 1
30+
def test_random_digit(self, faker, num_samples):
31+
samples = [faker.random_digit() for _ in range(num_samples * 10)]
32+
assert set(samples) == set(range(10))
2933

30-
assert self.fake.randomize_nb_elements(le=True, ge=True) == 10
34+
def test_random_digit_not_null(self, faker, num_samples):
35+
samples = [faker.random_digit_not_null() for _ in range(num_samples * 10)]
36+
assert set(samples) == set(range(1, 10))
3137

32-
assert self.fake.randomize_nb_elements(min=42) == 42
33-
assert self.fake.randomize_nb_elements(max=1) == 1
38+
def test_random_digit_or_empty(self, faker, num_samples):
39+
expected = set(range(10))
40+
expected.add('')
41+
samples = [faker.random_digit_or_empty() for _ in range(num_samples * 10)]
42+
assert set(samples) == expected
43+
44+
def test_random_digit_not_null_or_empty(self, faker, num_samples):
45+
expected = set(range(1, 10))
46+
expected.add('')
47+
samples = [faker.random_digit_not_null_or_empty() for _ in range(num_samples * 10)]
48+
assert set(samples) == expected
49+
50+
def test_random_number(self, faker):
51+
number = faker.random_number(10, True)
52+
assert len(str(number)) == 10
53+
54+
# Digits parameter < 0
55+
with pytest.raises(ValueError):
56+
number = faker.random_number(-1, True)
57+
58+
# Digits parameter < 1 with fix_len=True
59+
with pytest.raises(ValueError):
60+
number = faker.random_number(0, True)
61+
62+
@pytest.mark.parametrize('text,pattern', [
63+
('', r''),
64+
('abcd', r'abcd'),
65+
('#' * 100, r'[0-9]{100}'),
66+
('%' * 100, r'[1-9]{100}'),
67+
('!' * 100, r'[0-9]{,100}'),
68+
('@' * 100, r'[0-9]{,100}'),
69+
('##!abc %%@def##!' * 100, r'(?:[0-9]{2,3}abc [1-9]{2,3}def[0-9]{2,3}){100}'),
70+
('#@@#^?あ5漢!!%%@' * 100, r'(?:\d[1-9]{,2}\d\^\?あ5漢\d{,2}[1-9]{2}[1-9]*){100}'),
71+
], ids=[
72+
'empty_string',
73+
'no_valid_placeholders',
74+
'only_number_signs',
75+
'only_percent_signs',
76+
'only_exclamation_marks',
77+
'only_at_symbols',
78+
'with_ascii_characters',
79+
'with_other_symbols_and_non_ascii',
80+
])
81+
def test_numerify(self, faker, num_samples, text, pattern):
82+
for _ in range(num_samples):
83+
numerified = faker.numerify(text)
84+
assert re.fullmatch(pattern, numerified)
85+
86+
@pytest.mark.parametrize('text,letters,pattern', [
87+
('', string.ascii_letters, r''),
88+
('abcd', string.ascii_letters, r'abcd'),
89+
('???', string.ascii_letters, r'[0-9a-zA-Z]{3}'),
90+
('???', 'aBcDeFgHiJ12345', r'[1-5aBcDeFgHiJ]{3}'),
91+
('??Xr^#7p??', 'AbCdخあ5漢7Я', r'[AbCdخあ5漢7Я]{2}Xr\^#7p[AbCdخあ5漢7Я]{2}'),
92+
], ids=[
93+
'empty_string',
94+
'no_valid_placeholders',
95+
'letters_using_whole_ascii',
96+
'letters_using_ascii_subset',
97+
'pattern_with_other_symbols_and_letters_using_non_ascii',
98+
])
99+
def test_lexify(self, faker, num_samples, text, letters, pattern):
100+
for _ in range(num_samples):
101+
lexified = faker.lexify(text, letters=letters)
102+
assert re.fullmatch(pattern, lexified)
103+
104+
@pytest.mark.parametrize('text,letters,pattern', [
105+
('', string.ascii_letters, r''),
106+
('abcd', string.ascii_letters, r'abcd'),
107+
('???', string.ascii_letters, r'[0-9a-zA-Z]{3}'),
108+
('???', 'aBcDeFgHiJ12345', r'[1-5aBcDeFgHiJ]{3}'),
109+
('#%!@???', string.ascii_letters, r'\d[1-9]\d*[1-9]*[0-9a-zA-Z]{3}'),
110+
('#%!@???', 'aBcDeFgHiJ12345', r'\d[1-9]\d*[1-9]*[1-5aBcDeFgHiJ]{3}'),
111+
('#%!@??Xr7p??', 'AbCdخあ5漢7Я', r'\d[1-9]\d*[1-9]*[AbCdخあ5漢7Я]{2}Xr7p[AbCdخあ5漢7Я]{2}'),
112+
], ids=[
113+
'empty_string',
114+
'no_valid_placeholders',
115+
'simple_pattern_and_letters_using_whole_ascii',
116+
'simple_pattern_and_letters_using_ascii_subset',
117+
'more_complex_pattern_and_letters_using_whole_ascii',
118+
'more_complex_pattern_and_letters_using_ascii_subset',
119+
'more_complex_pattern_with_other_symbols_and_letters_using_non_ascii',
120+
])
121+
def test_bothify(self, faker, num_samples, text, letters, pattern):
122+
for _ in range(num_samples):
123+
bothified = faker.bothify(text, letters=letters)
124+
assert re.fullmatch(pattern, bothified)
125+
126+
@pytest.mark.parametrize('text,upper,pattern', [
127+
('', False, r''),
128+
('', True, r''),
129+
('abcd', False, r'abcd'),
130+
('abcd', True, r'abcd'),
131+
('^^^^', False, r'[0-9a-f]{4}'),
132+
('^^^^', True, r'[0-9A-F]{4}'),
133+
('Abc ^^^ %^^^?あ5漢!#^^', False, r'Abc [0-9a-f]{3} %[0-9a-f]{3}\?あ5漢!#[0-9a-f]{2}'),
134+
('Abc ^^^ %^^^?あ5漢!#^^', True, r'Abc [0-9A-F]{3} %[0-9A-F]{3}\?あ5漢!#[0-9A-F]{2}'),
135+
], ids=[
136+
'empty_string_lowercase',
137+
'empty_string_uppercase',
138+
'no_circumflex_lowercase',
139+
'no_circumflex_uppercase',
140+
'simple_pattern_lowercase',
141+
'simple_pattern_uppercase',
142+
'complex_pattern_lowercase',
143+
'complex_pattern_uppercase',
144+
])
145+
def test_hexify(self, faker, num_samples, text, upper, pattern):
146+
for _ in range(num_samples):
147+
hexified = faker.hexify(text, upper=upper)
148+
assert re.fullmatch(pattern, hexified)
149+
150+
def test_random_letter(self, faker, num_samples):
151+
for _ in range(num_samples):
152+
letter = faker.random_letter()
153+
assert letter.isalpha()
154+
155+
def test_random_lowercase_letter(self, faker, num_samples):
156+
for _ in range(num_samples):
157+
letter = faker.random_lowercase_letter()
158+
assert letter.isalpha() and letter.lower() == letter
159+
160+
def test_random_uppercase_letter(self, faker, num_samples):
161+
for _ in range(num_samples):
162+
letter = faker.random_uppercase_letter()
163+
assert letter.isalpha() and letter.upper() == letter
164+
165+
def test_random_element(self, faker, num_samples):
166+
# dicts not allowed because they introduce dependency on PYTHONHASHSEED
167+
with pytest.raises(ValueError):
168+
faker.random_element({})
169+
170+
choices = ('a', 'b', 'c', 'd')
171+
for _ in range(num_samples):
172+
assert faker.random_element(choices) in choices
173+
174+
choices = OrderedDict([('a', 5), ('b', 2), ('c', 2), ('d', 1)])
175+
for _ in range(num_samples):
176+
assert faker.random_element(choices) in choices
177+
178+
choices = OrderedDict([('a', 0.5), ('b', 0.2), ('c', 0.2), ('d', 0.1)])
179+
for _ in range(num_samples):
180+
assert faker.random_element(choices) in choices
181+
182+
def test_random_sample(self, faker):
183+
# Too many items requested
184+
with pytest.raises(ValueError):
185+
faker.random_sample('abcde', 6)
186+
187+
# Same length
188+
sample = faker.random_sample('abcd', 4)
189+
assert sorted(sample) == list('abcd')
190+
191+
sample = faker.random_sample('abcde', 5)
192+
assert sorted(sample) == list('abcde')
193+
194+
# Length = 3
195+
sample = faker.random_sample('abcde', 3)
196+
assert len(sample) == 3
197+
assert set(sample).issubset(set('abcde'))
198+
199+
# Length = 1
200+
sample = faker.random_sample('abcde', 1)
201+
assert len(sample) == 1
202+
assert set(sample).issubset(set('abcde'))
203+
204+
# Length = 0
205+
sample = faker.random_sample('abcde', 0)
206+
assert sample == []
207+
208+
def test_randomize_nb_elements(self, faker, num_samples):
209+
assert faker.randomize_nb_elements(number=1, le=True, ge=True) == 1
210+
assert faker.randomize_nb_elements(le=True, ge=True) == 10
211+
assert faker.randomize_nb_elements(min=42) == 42
212+
assert faker.randomize_nb_elements(max=1) == 1
34213

35214
number = 9999
36-
random_times = 100
37215
lower_bound = int(number * 0.6)
38216
upper_bound = int(number * 1.4)
39217

40-
for _ in range(random_times):
41-
res = self.fake.randomize_nb_elements(number=number, le=True)
218+
for _ in range(num_samples):
219+
res = faker.randomize_nb_elements(number=number, le=True)
42220
assert res >= lower_bound
43221
assert res <= number, "'{}' is not <= than '{}'".format(res, number)
44222

45-
for _ in range(random_times):
46-
res = self.fake.randomize_nb_elements(number=number, ge=True)
47-
assert res >= number
48-
assert res <= upper_bound
223+
for _ in range(num_samples):
224+
res = faker.randomize_nb_elements(number=number, ge=True)
225+
assert number <= res <= upper_bound
49226

50-
for _ in range(random_times):
51-
res = self.fake.randomize_nb_elements(number=number)
52-
assert res >= lower_bound
53-
assert res <= upper_bound
227+
for _ in range(num_samples):
228+
res = faker.randomize_nb_elements(number=number)
229+
assert lower_bound <= res <= upper_bound

tests/providers/conftest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import locale as pylocale
2+
import re
3+
4+
import pytest
5+
6+
from faker import Faker
7+
from faker.contrib.pytest.plugin import DEFAULT_SEED
8+
9+
LOCALE_TEST_CLASS_NAME_REGEX = re.compile(
10+
r'^Test(?P<language>[A-Z][a-z]{1,2})(?P<region>[A-Z][a-z])$',
11+
)
12+
13+
14+
@pytest.fixture(scope='class', autouse=True)
15+
def _class_locale_faker(request):
16+
if not request.cls:
17+
return None
18+
class_name = request.cls.__name__
19+
match = LOCALE_TEST_CLASS_NAME_REGEX.fullmatch(class_name)
20+
if not match:
21+
return None
22+
locale = '{language}_{region}'.format(**match.groupdict())
23+
locale = pylocale.normalize(locale).split('.')[0]
24+
return Faker(locale=locale)
25+
26+
27+
@pytest.fixture(autouse=True)
28+
def faker(_class_locale_faker, faker):
29+
if not _class_locale_faker:
30+
return faker
31+
_class_locale_faker.seed_instance(DEFAULT_SEED)
32+
return _class_locale_faker
33+
34+
35+
@pytest.fixture(scope='class', autouse=True)
36+
def num_samples(request):
37+
try:
38+
num = int(request.cls.num_samples)
39+
except AttributeError:
40+
num = 100
41+
return num

0 commit comments

Comments
 (0)