Skip to content

Commit 6b7c37e

Browse files
committed
Improve tests
* Move tests to the right test file (e.g. tests for `dotenv.main.get_key` go to `tests.test_main.py`, not `tests.test_cli.py`. * Check logged warnings for more functions. For instance, that uncovered unexpected extra warnings when passing a non-existent file as argument. * Remove tests for properties already checked at a lower level. For instance, it's unnecessary to call `get_key` with weird file content because that's already tested with the parser. * Follow the Act/Arrange/Assert (AAA) pattern. This clarifies what is tested in each test function. For instance, using this, we test only one thing at a time, which makes the test easier to read and potential failures easier to interpret.
1 parent a1bdf79 commit 6b7c37e

File tree

4 files changed

+472
-383
lines changed

4 files changed

+472
-383
lines changed

tests/test_cli.py

Lines changed: 70 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
# -*- coding: utf-8 -*-
2-
import os
3-
42
import pytest
53
import sh
64

@@ -9,143 +7,65 @@
97
from dotenv.version import __version__
108

119

12-
def test_get_key(dotenv_file):
13-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
14-
stored_value = dotenv.get_key(dotenv_file, 'HELLO')
15-
assert stored_value == 'WORLD'
16-
sh.rm(dotenv_file)
17-
assert dotenv.get_key(dotenv_file, 'HELLO') is None
18-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
19-
assert success is None
20-
21-
22-
def test_set_key(dotenv_file):
23-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
24-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'foo', 'bar')
25-
assert dotenv.get_key(dotenv_file, 'HELLO') == 'WORLD'
26-
27-
with open(dotenv_file, 'r') as fp:
28-
assert 'HELLO="WORLD"\nfoo="bar"' == fp.read().strip()
29-
30-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD 2')
31-
assert dotenv.get_key(dotenv_file, 'HELLO') == 'WORLD 2'
32-
assert dotenv.get_key(dotenv_file, 'foo') == 'bar'
33-
34-
with open(dotenv_file, 'r') as fp:
35-
assert 'HELLO="WORLD 2"\nfoo="bar"' == fp.read().strip()
36-
37-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, "HELLO", "WORLD\n3")
38-
39-
with open(dotenv_file, "r") as fp:
40-
assert 'HELLO="WORLD\n3"\nfoo="bar"' == fp.read().strip()
41-
42-
43-
def test_set_key_permission_error(dotenv_file):
44-
os.chmod(dotenv_file, 0o000)
45-
46-
with pytest.raises(Exception):
47-
dotenv.set_key(dotenv_file, "HELLO", "WORLD")
48-
49-
os.chmod(dotenv_file, 0o600)
50-
with open(dotenv_file, "r") as fp:
51-
assert fp.read() == ""
52-
53-
5410
def test_list(cli, dotenv_file):
55-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
11+
with open(dotenv_file, "w") as f:
12+
f.write("a=b")
13+
5614
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'list'])
57-
assert result.exit_code == 0, result.output
58-
assert result.output == 'HELLO=WORLD\n'
5915

16+
assert (result.exit_code, result.output) == (0, result.output)
6017

61-
def test_get_cli(cli, dotenv_file):
62-
cli.invoke(dotenv_cli, ['--file', dotenv_file, 'set', 'HELLO', "WORLD 1"])
63-
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'get', 'HELLO'])
64-
assert result.exit_code == 0, result.output
65-
assert result.output == 'HELLO=WORLD 1\n'
6618

19+
def test_list_non_existent_file(cli):
20+
result = cli.invoke(dotenv_cli, ['--file', 'nx_file', 'list'])
6721

68-
def test_list_wo_file(cli):
69-
result = cli.invoke(dotenv_cli, ['--file', 'doesnotexists', 'list'])
7022
assert result.exit_code == 2, result.output
7123
assert 'Invalid value for "-f"' in result.output
7224

7325

74-
def test_empty_value(dotenv_file):
75-
with open(dotenv_file, "w") as f:
76-
f.write("TEST=")
77-
assert dotenv.get_key(dotenv_file, "TEST") == ""
78-
79-
80-
def test_key_value_without_quotes(dotenv_file):
81-
with open(dotenv_file, 'w') as f:
82-
f.write("TEST = value \n")
83-
assert dotenv.get_key(dotenv_file, 'TEST') == "value"
26+
def test_list_no_file(cli):
27+
result = cli.invoke(dotenv.cli.list, [])
8428

29+
assert (result.exit_code, result.output) == (1, "")
8530

86-
def test_key_value_without_quotes_with_spaces(dotenv_file):
87-
with open(dotenv_file, 'w') as f:
88-
f.write('TEST = " with spaces " \n')
89-
assert dotenv.get_key(dotenv_file, 'TEST') == " with spaces "
9031

32+
def test_get_existing_value(cli, dotenv_file):
33+
with open(dotenv_file, "w") as f:
34+
f.write("a=b")
9135

92-
def test_value_with_double_quotes(dotenv_file):
93-
with open(dotenv_file, 'w') as f:
94-
f.write('TEST="two words"\n')
95-
assert dotenv.get_key(dotenv_file, 'TEST') == 'two words'
96-
36+
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'get', 'a'])
9737

98-
def test_value_with_simple_quotes(dotenv_file):
99-
with open(dotenv_file, 'w') as f:
100-
f.write("TEST='two words'\n")
101-
assert dotenv.get_key(dotenv_file, 'TEST') == 'two words'
38+
assert (result.exit_code, result.output) == (0, "a=b\n")
10239

10340

104-
def test_value_with_special_characters(dotenv_file):
105-
with open(dotenv_file, 'w') as f:
106-
f.write(r'TEST="}=&~{,(\5%{&;"')
107-
assert dotenv.get_key(dotenv_file, 'TEST') == r'}=&~{,(\5%{&;'
41+
def test_get_non_existent_value(cli, dotenv_file):
42+
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'get', 'a'])
10843

44+
assert (result.exit_code, result.output) == (1, "")
10945

110-
def test_value_with_new_lines(dotenv_file):
111-
with open(dotenv_file, 'w') as f:
112-
f.write('TEST="a\nb"')
113-
assert dotenv.get_key(dotenv_file, 'TEST') == "a\nb"
11446

47+
def test_get_no_file(cli):
48+
result = cli.invoke(dotenv_cli, ['--file', 'nx_file', 'get', 'a'])
11549

116-
def test_value_after_comment(dotenv_file):
117-
with open(dotenv_file, "w") as f:
118-
f.write("# comment\nTEST=a")
119-
assert dotenv.get_key(dotenv_file, "TEST") == "a"
50+
assert result.exit_code == 2
51+
assert 'Invalid value for "-f"' in result.output
12052

12153

122-
def test_unset_ok(dotenv_file):
54+
def test_unset_existing_value(cli, dotenv_file):
12355
with open(dotenv_file, "w") as f:
124-
f.write("a=b\nc=d")
125-
126-
success, key_to_unset = dotenv.unset_key(dotenv_file, "a")
56+
f.write("a=b")
12757

128-
assert success is True
129-
assert key_to_unset == "a"
130-
with open(dotenv_file, "r") as f:
131-
assert f.read() == "c=d"
58+
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'a'])
13259

60+
assert (result.exit_code, result.output) == (0, "Successfully removed a\n")
61+
assert open(dotenv_file, "r").read() == ""
13362

134-
def test_unset_non_existing_file():
135-
success, key_to_unset = dotenv.unset_key('/non-existing', 'HELLO')
13663

137-
assert success is None
64+
def test_unset_non_existent_value(cli, dotenv_file):
65+
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'a'])
13866

139-
140-
def test_unset_cli(cli, dotenv_file):
141-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'TESTHELLO', 'WORLD')
142-
dotenv.get_key(dotenv_file, 'TESTHELLO') == 'WORLD'
143-
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'TESTHELLO'])
144-
assert result.exit_code == 0, result.output
145-
assert result.output == 'Successfully removed TESTHELLO\n'
146-
dotenv.get_key(dotenv_file, 'TESTHELLO') is None
147-
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'TESTHELLO'])
148-
assert result.exit_code == 1, result.output
67+
assert (result.exit_code, result.output) == (1, "")
68+
assert open(dotenv_file, "r").read() == ""
14969

15070

15171
@pytest.mark.parametrize(
@@ -157,110 +77,75 @@ def test_unset_cli(cli, dotenv_file):
15777
("auto", "HELLO", "HELLO WORLD", 'HELLO="HELLO WORLD"\n'),
15878
)
15979
)
160-
def test_console_script(quote_mode, variable, value, expected, dotenv_file):
161-
sh.dotenv('-f', dotenv_file, '-q', quote_mode, 'set', variable, value)
80+
def test_set_options(cli, dotenv_file, quote_mode, variable, value, expected):
81+
result = cli.invoke(
82+
dotenv_cli,
83+
["--file", dotenv_file, "--quote", quote_mode, "set", variable, value]
84+
)
16285

163-
result = sh.cat(dotenv_file)
86+
assert (result.exit_code, result.output) == (0, "{}={}\n".format(variable, value))
87+
assert open(dotenv_file, "r").read() == expected
16488

165-
assert result == expected
16689

90+
def test_set_non_existent_file(cli):
91+
result = cli.invoke(dotenv.cli.set, ["a", "b"])
16792

168-
def test_set_non_existing_file(cli):
169-
result = cli.invoke(dotenv.cli.set, ['my_key', 'my_value'])
93+
assert (result.exit_code, result.output) == (1, "")
17094

171-
assert result.exit_code != 0
17295

96+
def test_set_no_file(cli):
97+
result = cli.invoke(dotenv_cli, ["--file", "nx_file", "set"])
17398

174-
def test_get_non_existing_file(cli):
175-
result = cli.invoke(dotenv.cli.get, ['my_key'])
99+
assert result.exit_code == 2
100+
assert 'Invalid value for "-f"' in result.output
176101

177-
assert result.exit_code != 0
178102

103+
def test_get_default_path(tmp_path):
104+
sh.cd(str(tmp_path))
105+
with open(str(tmp_path / ".env"), "w") as f:
106+
f.write("a=b")
179107

180-
def test_list_non_existing_file(cli):
181-
result = cli.invoke(dotenv.cli.set, [])
108+
result = sh.dotenv("get", "a")
182109

183-
assert result.exit_code != 0
110+
assert result == "a=b\n"
184111

185112

186-
def test_default_path(tmp_path):
113+
def test_run(tmp_path):
187114
sh.cd(str(tmp_path))
188-
sh.touch(tmp_path / '.env')
189-
sh.dotenv('set', 'HELLO', 'WORLD')
190-
191-
result = sh.dotenv('get', 'HELLO')
192-
193-
assert result == 'HELLO=WORLD\n'
194-
195-
196-
def test_get_key_with_interpolation(dotenv_file):
197-
sh.touch(dotenv_file)
198-
dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
199-
dotenv.set_key(dotenv_file, 'FOO', '${HELLO}')
200-
dotenv.set_key(dotenv_file, 'BAR', 'CONCATENATED_${HELLO}_POSIX_VAR')
201-
202-
with open(dotenv_file) as f:
203-
lines = f.readlines()
204-
assert lines == [
205-
'HELLO="WORLD"\n',
206-
'FOO="${HELLO}"\n',
207-
'BAR="CONCATENATED_${HELLO}_POSIX_VAR"\n',
208-
]
209-
210-
# test replace from variable in file
211-
stored_value = dotenv.get_key(dotenv_file, 'FOO')
212-
assert stored_value == 'WORLD'
213-
stored_value = dotenv.get_key(dotenv_file, 'BAR')
214-
assert stored_value == 'CONCATENATED_WORLD_POSIX_VAR'
215-
# test replace from environ taking precedence over file
216-
os.environ["HELLO"] = "TAKES_PRECEDENCE"
217-
stored_value = dotenv.get_key(dotenv_file, 'FOO')
218-
assert stored_value == "TAKES_PRECEDENCE"
219-
220-
221-
def test_get_key_with_interpolation_of_unset_variable(dotenv_file):
222-
dotenv.set_key(dotenv_file, 'FOO', '${NOT_SET}')
223-
# test unavailable replacement returns empty string
224-
stored_value = dotenv.get_key(dotenv_file, 'FOO')
225-
assert stored_value == ''
226-
# unless present in environment
227-
os.environ['NOT_SET'] = 'BAR'
228-
stored_value = dotenv.get_key(dotenv_file, 'FOO')
229-
assert stored_value == 'BAR'
230-
del(os.environ['NOT_SET'])
115+
dotenv_file = str(tmp_path / ".env")
116+
with open(dotenv_file, "w") as f:
117+
f.write("a=b")
231118

119+
result = sh.dotenv("run", "printenv", "a")
232120

233-
def test_run(tmp_path):
234-
dotenv_file = tmp_path / '.env'
235-
dotenv_file.touch()
236-
sh.cd(str(tmp_path))
237-
dotenv.set_key(str(dotenv_file), 'FOO', 'BAR')
238-
result = sh.dotenv('run', 'printenv', 'FOO').strip()
239-
assert result == 'BAR'
121+
assert result == "b\n"
240122

241123

242-
def test_run_with_other_env(tmp_path):
243-
dotenv_name = 'dotenv'
244-
dotenv_file = tmp_path / dotenv_name
245-
dotenv_file.touch()
246-
sh.cd(str(tmp_path))
247-
sh.dotenv('--file', dotenv_name, 'set', 'FOO', 'BAR')
248-
result = sh.dotenv('--file', dotenv_name, 'run', 'printenv', 'FOO').strip()
249-
assert result == 'BAR'
124+
def test_run_with_other_env(dotenv_file):
125+
with open(dotenv_file, "w") as f:
126+
f.write("a=b")
127+
128+
result = sh.dotenv("--file", dotenv_file, "run", "printenv", "a")
129+
130+
assert result == "b\n"
250131

251132

252133
def test_run_without_cmd(cli):
253134
result = cli.invoke(dotenv_cli, ['run'])
254-
assert result.exit_code != 0
135+
136+
assert result.exit_code == 2
137+
assert 'Invalid value for "-f"' in result.output
255138

256139

257140
def test_run_with_invalid_cmd(cli):
258141
result = cli.invoke(dotenv_cli, ['run', 'i_do_not_exist'])
259-
assert result.exit_code != 0
142+
143+
assert result.exit_code == 2
144+
assert 'Invalid value for "-f"' in result.output
260145

261146

262147
def test_run_with_version(cli):
263148
result = cli.invoke(dotenv_cli, ['--version'])
264-
print(vars(result))
149+
265150
assert result.exit_code == 0
266151
assert result.output.strip().endswith(__version__)

0 commit comments

Comments
 (0)